blob: 815564fcbe182f74a4d823cc8ed5e10f06ea1fb2 [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"
Jamie Madillb1a85f42014-08-19 15:23:24 -040019#include "compiler/translator/HashNames.h"
20#include "compiler/translator/IntermNode.h"
21#include "compiler/translator/SymbolTable.h"
22
23namespace
24{
25
Arun Patole9dea48f2015-04-02 11:45:09 +053026const float kPi = 3.14159265358979323846f;
27const float kDegreesToRadiansMultiplier = kPi / 180.0f;
28const float kRadiansToDegreesMultiplier = 180.0f / kPi;
29
Jamie Madillb1a85f42014-08-19 15:23:24 -040030TPrecision GetHigherPrecision(TPrecision left, TPrecision right)
31{
32 return left > right ? left : right;
33}
34
35bool ValidateMultiplication(TOperator op, const TType &left, const TType &right)
36{
37 switch (op)
38 {
39 case EOpMul:
40 case EOpMulAssign:
41 return left.getNominalSize() == right.getNominalSize() &&
42 left.getSecondarySize() == right.getSecondarySize();
43 case EOpVectorTimesScalar:
44 case EOpVectorTimesScalarAssign:
45 return true;
46 case EOpVectorTimesMatrix:
47 return left.getNominalSize() == right.getRows();
48 case EOpVectorTimesMatrixAssign:
49 return left.getNominalSize() == right.getRows() &&
50 left.getNominalSize() == right.getCols();
51 case EOpMatrixTimesVector:
52 return left.getCols() == right.getNominalSize();
53 case EOpMatrixTimesScalar:
54 case EOpMatrixTimesScalarAssign:
55 return true;
56 case EOpMatrixTimesMatrix:
57 return left.getCols() == right.getRows();
58 case EOpMatrixTimesMatrixAssign:
59 return left.getCols() == right.getCols() &&
60 left.getRows() == right.getRows();
61
62 default:
63 UNREACHABLE();
64 return false;
65 }
66}
67
68bool CompareStructure(const TType& leftNodeType,
Jamie Madillb11e2482015-05-04 14:21:22 -040069 const TConstantUnion *rightUnionArray,
70 const TConstantUnion *leftUnionArray);
Jamie Madillb1a85f42014-08-19 15:23:24 -040071
72bool CompareStruct(const TType &leftNodeType,
Jamie Madillb11e2482015-05-04 14:21:22 -040073 const TConstantUnion *rightUnionArray,
74 const TConstantUnion *leftUnionArray)
Jamie Madillb1a85f42014-08-19 15:23:24 -040075{
76 const TFieldList &fields = leftNodeType.getStruct()->fields();
77
78 size_t structSize = fields.size();
79 size_t index = 0;
80
81 for (size_t j = 0; j < structSize; j++)
82 {
83 size_t size = fields[j]->type()->getObjectSize();
84 for (size_t i = 0; i < size; i++)
85 {
86 if (fields[j]->type()->getBasicType() == EbtStruct)
87 {
88 if (!CompareStructure(*fields[j]->type(),
89 &rightUnionArray[index],
90 &leftUnionArray[index]))
91 {
92 return false;
93 }
94 }
95 else
96 {
97 if (leftUnionArray[index] != rightUnionArray[index])
98 return false;
99 index++;
100 }
101 }
102 }
103 return true;
104}
105
106bool CompareStructure(const TType &leftNodeType,
Jamie Madillb11e2482015-05-04 14:21:22 -0400107 const TConstantUnion *rightUnionArray,
108 const TConstantUnion *leftUnionArray)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400109{
110 if (leftNodeType.isArray())
111 {
112 TType typeWithoutArrayness = leftNodeType;
113 typeWithoutArrayness.clearArrayness();
114
115 size_t arraySize = leftNodeType.getArraySize();
116
117 for (size_t i = 0; i < arraySize; ++i)
118 {
119 size_t offset = typeWithoutArrayness.getObjectSize() * i;
120 if (!CompareStruct(typeWithoutArrayness,
121 &rightUnionArray[offset],
122 &leftUnionArray[offset]))
123 {
124 return false;
125 }
126 }
127 }
128 else
129 {
130 return CompareStruct(leftNodeType, rightUnionArray, leftUnionArray);
131 }
132 return true;
133}
134
Arun Patole274f0702015-05-05 13:33:30 +0530135TConstantUnion *Vectorize(const TConstantUnion &constant, size_t size)
136{
137 TConstantUnion *constUnion = new TConstantUnion[size];
138 for (unsigned int i = 0; i < size; ++i)
139 constUnion[i] = constant;
140
141 return constUnion;
142}
143
Arun Patolebf790422015-05-18 17:53:04 +0530144void UndefinedConstantFoldingError(const TSourceLoc &loc, TOperator op, TBasicType basicType,
145 TInfoSink &infoSink, TConstantUnion *result)
146{
147 std::stringstream constantFoldingErrorStream;
148 constantFoldingErrorStream << "'" << GetOperatorString(op)
149 << "' operation result is undefined for the values passed in";
150 infoSink.info.message(EPrefixWarning, loc, constantFoldingErrorStream.str().c_str());
151
152 switch (basicType)
153 {
154 case EbtFloat :
155 result->setFConst(0.0f);
156 break;
157 case EbtInt:
158 result->setIConst(0);
159 break;
160 case EbtUInt:
161 result->setUConst(0u);
162 break;
163 case EbtBool:
164 result->setBConst(false);
165 break;
166 default:
167 break;
168 }
169}
170
Arun Patole1155ddd2015-06-05 18:04:36 +0530171float VectorLength(TConstantUnion *paramArray, size_t paramArraySize)
172{
173 float result = 0.0f;
174 for (size_t i = 0; i < paramArraySize; i++)
175 {
176 float f = paramArray[i].getFConst();
177 result += f * f;
178 }
179 return sqrtf(result);
180}
181
182float VectorDotProduct(TConstantUnion *paramArray1, TConstantUnion *paramArray2, size_t paramArraySize)
183{
184 float result = 0.0f;
185 for (size_t i = 0; i < paramArraySize; i++)
186 result += paramArray1[i].getFConst() * paramArray2[i].getFConst();
187 return result;
188}
189
Olli Etuahob43846e2015-06-02 18:18:57 +0300190TIntermTyped *CreateFoldedNode(TConstantUnion *constArray, const TIntermTyped *originalNode)
191{
192 if (constArray == nullptr)
193 {
194 return nullptr;
195 }
196 TIntermTyped *folded = new TIntermConstantUnion(constArray, originalNode->getType());
197 folded->getTypePointer()->setQualifier(EvqConst);
198 folded->setLine(originalNode->getLine());
199 return folded;
200}
201
Jamie Madillb1a85f42014-08-19 15:23:24 -0400202} // namespace anonymous
203
204
205////////////////////////////////////////////////////////////////
206//
207// Member functions of the nodes used for building the tree.
208//
209////////////////////////////////////////////////////////////////
210
Olli Etuahod2a67b92014-10-21 16:42:57 +0300211void TIntermTyped::setTypePreservePrecision(const TType &t)
212{
213 TPrecision precision = getPrecision();
214 mType = t;
215 ASSERT(mType.getBasicType() != EbtBool || precision == EbpUndefined);
216 mType.setPrecision(precision);
217}
218
Jamie Madillb1a85f42014-08-19 15:23:24 -0400219#define REPLACE_IF_IS(node, type, original, replacement) \
220 if (node == original) { \
221 node = static_cast<type *>(replacement); \
222 return true; \
223 }
224
225bool TIntermLoop::replaceChildNode(
226 TIntermNode *original, TIntermNode *replacement)
227{
228 REPLACE_IF_IS(mInit, TIntermNode, original, replacement);
229 REPLACE_IF_IS(mCond, TIntermTyped, original, replacement);
230 REPLACE_IF_IS(mExpr, TIntermTyped, original, replacement);
231 REPLACE_IF_IS(mBody, TIntermNode, original, replacement);
232 return false;
233}
234
Jamie Madillb1a85f42014-08-19 15:23:24 -0400235bool TIntermBranch::replaceChildNode(
236 TIntermNode *original, TIntermNode *replacement)
237{
238 REPLACE_IF_IS(mExpression, TIntermTyped, original, replacement);
239 return false;
240}
241
Jamie Madillb1a85f42014-08-19 15:23:24 -0400242bool TIntermBinary::replaceChildNode(
243 TIntermNode *original, TIntermNode *replacement)
244{
245 REPLACE_IF_IS(mLeft, TIntermTyped, original, replacement);
246 REPLACE_IF_IS(mRight, TIntermTyped, original, replacement);
247 return false;
248}
249
Jamie Madillb1a85f42014-08-19 15:23:24 -0400250bool TIntermUnary::replaceChildNode(
251 TIntermNode *original, TIntermNode *replacement)
252{
253 REPLACE_IF_IS(mOperand, TIntermTyped, original, replacement);
254 return false;
255}
256
Jamie Madillb1a85f42014-08-19 15:23:24 -0400257bool TIntermAggregate::replaceChildNode(
258 TIntermNode *original, TIntermNode *replacement)
259{
260 for (size_t ii = 0; ii < mSequence.size(); ++ii)
261 {
262 REPLACE_IF_IS(mSequence[ii], TIntermNode, original, replacement);
263 }
264 return false;
265}
266
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300267bool TIntermAggregate::replaceChildNodeWithMultiple(TIntermNode *original, TIntermSequence replacements)
268{
269 for (auto it = mSequence.begin(); it < mSequence.end(); ++it)
270 {
271 if (*it == original)
272 {
273 it = mSequence.erase(it);
Olli Etuaho8fee0ab2015-04-23 14:52:46 +0300274 mSequence.insert(it, replacements.begin(), replacements.end());
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300275 return true;
276 }
277 }
278 return false;
279}
280
Olli Etuahoa6f22092015-05-08 18:31:10 +0300281bool TIntermAggregate::insertChildNodes(TIntermSequence::size_type position, TIntermSequence insertions)
282{
283 TIntermSequence::size_type itPosition = 0;
284 for (auto it = mSequence.begin(); it < mSequence.end(); ++it)
285 {
286 if (itPosition == position)
287 {
288 mSequence.insert(it, insertions.begin(), insertions.end());
289 return true;
290 }
291 ++itPosition;
292 }
293 return false;
294}
295
Olli Etuahod2a67b92014-10-21 16:42:57 +0300296void TIntermAggregate::setPrecisionFromChildren()
297{
Olli Etuahoa4aa4e32015-06-04 15:54:30 +0300298 mGotPrecisionFromChildren = true;
Olli Etuahod2a67b92014-10-21 16:42:57 +0300299 if (getBasicType() == EbtBool)
300 {
301 mType.setPrecision(EbpUndefined);
302 return;
303 }
304
305 TPrecision precision = EbpUndefined;
306 TIntermSequence::iterator childIter = mSequence.begin();
307 while (childIter != mSequence.end())
308 {
309 TIntermTyped *typed = (*childIter)->getAsTyped();
310 if (typed)
311 precision = GetHigherPrecision(typed->getPrecision(), precision);
312 ++childIter;
313 }
314 mType.setPrecision(precision);
315}
316
317void TIntermAggregate::setBuiltInFunctionPrecision()
318{
319 // All built-ins returning bool should be handled as ops, not functions.
320 ASSERT(getBasicType() != EbtBool);
321
322 TPrecision precision = EbpUndefined;
323 TIntermSequence::iterator childIter = mSequence.begin();
324 while (childIter != mSequence.end())
325 {
326 TIntermTyped *typed = (*childIter)->getAsTyped();
327 // ESSL spec section 8: texture functions get their precision from the sampler.
328 if (typed && IsSampler(typed->getBasicType()))
329 {
330 precision = typed->getPrecision();
331 break;
332 }
333 ++childIter;
334 }
335 // ESSL 3.0 spec section 8: textureSize always gets highp precision.
336 // All other functions that take a sampler are assumed to be texture functions.
337 if (mName.find("textureSize") == 0)
338 mType.setPrecision(EbpHigh);
339 else
340 mType.setPrecision(precision);
341}
342
Jamie Madillb1a85f42014-08-19 15:23:24 -0400343bool TIntermSelection::replaceChildNode(
344 TIntermNode *original, TIntermNode *replacement)
345{
346 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
347 REPLACE_IF_IS(mTrueBlock, TIntermNode, original, replacement);
348 REPLACE_IF_IS(mFalseBlock, TIntermNode, original, replacement);
349 return false;
350}
351
Olli Etuahoa3a36662015-02-17 13:46:51 +0200352bool TIntermSwitch::replaceChildNode(
353 TIntermNode *original, TIntermNode *replacement)
354{
355 REPLACE_IF_IS(mInit, TIntermTyped, original, replacement);
356 REPLACE_IF_IS(mStatementList, TIntermAggregate, original, replacement);
357 return false;
358}
359
360bool TIntermCase::replaceChildNode(
361 TIntermNode *original, TIntermNode *replacement)
362{
363 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
364 return false;
365}
366
Jamie Madillb1a85f42014-08-19 15:23:24 -0400367//
368// Say whether or not an operation node changes the value of a variable.
369//
370bool TIntermOperator::isAssignment() const
371{
372 switch (mOp)
373 {
374 case EOpPostIncrement:
375 case EOpPostDecrement:
376 case EOpPreIncrement:
377 case EOpPreDecrement:
378 case EOpAssign:
379 case EOpAddAssign:
380 case EOpSubAssign:
381 case EOpMulAssign:
382 case EOpVectorTimesMatrixAssign:
383 case EOpVectorTimesScalarAssign:
384 case EOpMatrixTimesScalarAssign:
385 case EOpMatrixTimesMatrixAssign:
386 case EOpDivAssign:
Olli Etuahoff805cc2015-02-13 10:59:34 +0200387 case EOpIModAssign:
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200388 case EOpBitShiftLeftAssign:
389 case EOpBitShiftRightAssign:
390 case EOpBitwiseAndAssign:
391 case EOpBitwiseXorAssign:
392 case EOpBitwiseOrAssign:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400393 return true;
394 default:
395 return false;
396 }
397}
398
Olli Etuaho8f76bcc2015-06-02 13:54:20 +0300399bool TIntermOperator::isMultiplication() const
400{
401 switch (mOp)
402 {
403 case EOpMul:
404 case EOpMatrixTimesMatrix:
405 case EOpMatrixTimesVector:
406 case EOpMatrixTimesScalar:
407 case EOpVectorTimesMatrix:
408 case EOpVectorTimesScalar:
409 return true;
410 default:
411 return false;
412 }
413}
414
Jamie Madillb1a85f42014-08-19 15:23:24 -0400415//
416// returns true if the operator is for one of the constructors
417//
418bool TIntermOperator::isConstructor() const
419{
420 switch (mOp)
421 {
422 case EOpConstructVec2:
423 case EOpConstructVec3:
424 case EOpConstructVec4:
425 case EOpConstructMat2:
426 case EOpConstructMat3:
427 case EOpConstructMat4:
428 case EOpConstructFloat:
429 case EOpConstructIVec2:
430 case EOpConstructIVec3:
431 case EOpConstructIVec4:
432 case EOpConstructInt:
433 case EOpConstructUVec2:
434 case EOpConstructUVec3:
435 case EOpConstructUVec4:
436 case EOpConstructUInt:
437 case EOpConstructBVec2:
438 case EOpConstructBVec3:
439 case EOpConstructBVec4:
440 case EOpConstructBool:
441 case EOpConstructStruct:
442 return true;
443 default:
444 return false;
445 }
446}
447
448//
449// Make sure the type of a unary operator is appropriate for its
450// combination of operation and operand type.
451//
Olli Etuahof6c694b2015-03-26 14:50:53 +0200452void TIntermUnary::promote(const TType *funcReturnType)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400453{
454 switch (mOp)
455 {
Olli Etuahodca3e792015-03-26 13:24:04 +0200456 case EOpFloatBitsToInt:
457 case EOpFloatBitsToUint:
Olli Etuahoe8d2c072015-01-08 16:33:54 +0200458 case EOpIntBitsToFloat:
459 case EOpUintBitsToFloat:
Olli Etuahodca3e792015-03-26 13:24:04 +0200460 case EOpPackSnorm2x16:
461 case EOpPackUnorm2x16:
462 case EOpPackHalf2x16:
Olli Etuaho7700ff62015-01-15 12:16:29 +0200463 case EOpUnpackSnorm2x16:
464 case EOpUnpackUnorm2x16:
Olli Etuahodca3e792015-03-26 13:24:04 +0200465 mType.setPrecision(EbpHigh);
Arun Patole6b19d762015-02-19 09:40:39 +0530466 break;
Olli Etuahodca3e792015-03-26 13:24:04 +0200467 case EOpUnpackHalf2x16:
468 mType.setPrecision(EbpMedium);
469 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400470 default:
Olli Etuahodca3e792015-03-26 13:24:04 +0200471 setType(mOperand->getType());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400472 }
473
Olli Etuahof6c694b2015-03-26 14:50:53 +0200474 if (funcReturnType != nullptr)
475 {
476 if (funcReturnType->getBasicType() == EbtBool)
477 {
478 // Bool types should not have precision.
479 setType(*funcReturnType);
480 }
481 else
482 {
483 // Precision of the node has been set based on the operand.
484 setTypePreservePrecision(*funcReturnType);
485 }
486 }
487
Jamie Madillb1a85f42014-08-19 15:23:24 -0400488 mType.setQualifier(EvqTemporary);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400489}
490
491//
492// Establishes the type of the resultant operation, as well as
493// makes the operator the correct one for the operands.
494//
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200495// For lots of operations it should already be established that the operand
496// combination is valid, but returns false if operator can't work on operands.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400497//
498bool TIntermBinary::promote(TInfoSink &infoSink)
499{
Olli Etuahoe79904c2015-03-18 16:56:42 +0200500 ASSERT(mLeft->isArray() == mRight->isArray());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400501
Jamie Madillb1a85f42014-08-19 15:23:24 -0400502 //
503 // Base assumption: just make the type the same as the left
504 // operand. Then only deviations from this need be coded.
505 //
506 setType(mLeft->getType());
507
508 // The result gets promoted to the highest precision.
509 TPrecision higherPrecision = GetHigherPrecision(
510 mLeft->getPrecision(), mRight->getPrecision());
511 getTypePointer()->setPrecision(higherPrecision);
512
513 // Binary operations results in temporary variables unless both
514 // operands are const.
515 if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst)
516 {
517 getTypePointer()->setQualifier(EvqTemporary);
518 }
519
520 const int nominalSize =
521 std::max(mLeft->getNominalSize(), mRight->getNominalSize());
522
523 //
524 // All scalars or structs. Code after this test assumes this case is removed!
525 //
526 if (nominalSize == 1)
527 {
528 switch (mOp)
529 {
530 //
531 // Promote to conditional
532 //
533 case EOpEqual:
534 case EOpNotEqual:
535 case EOpLessThan:
536 case EOpGreaterThan:
537 case EOpLessThanEqual:
538 case EOpGreaterThanEqual:
539 setType(TType(EbtBool, EbpUndefined));
540 break;
541
542 //
543 // And and Or operate on conditionals
544 //
545 case EOpLogicalAnd:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200546 case EOpLogicalXor:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400547 case EOpLogicalOr:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200548 ASSERT(mLeft->getBasicType() == EbtBool && mRight->getBasicType() == EbtBool);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400549 setType(TType(EbtBool, EbpUndefined));
550 break;
551
552 default:
553 break;
554 }
555 return true;
556 }
557
558 // If we reach here, at least one of the operands is vector or matrix.
559 // The other operand could be a scalar, vector, or matrix.
560 // Can these two operands be combined?
561 //
562 TBasicType basicType = mLeft->getBasicType();
563 switch (mOp)
564 {
565 case EOpMul:
566 if (!mLeft->isMatrix() && mRight->isMatrix())
567 {
568 if (mLeft->isVector())
569 {
570 mOp = EOpVectorTimesMatrix;
571 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700572 static_cast<unsigned char>(mRight->getCols()), 1));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400573 }
574 else
575 {
576 mOp = EOpMatrixTimesScalar;
577 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700578 static_cast<unsigned char>(mRight->getCols()), static_cast<unsigned char>(mRight->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400579 }
580 }
581 else if (mLeft->isMatrix() && !mRight->isMatrix())
582 {
583 if (mRight->isVector())
584 {
585 mOp = EOpMatrixTimesVector;
586 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700587 static_cast<unsigned char>(mLeft->getRows()), 1));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400588 }
589 else
590 {
591 mOp = EOpMatrixTimesScalar;
592 }
593 }
594 else if (mLeft->isMatrix() && mRight->isMatrix())
595 {
596 mOp = EOpMatrixTimesMatrix;
597 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700598 static_cast<unsigned char>(mRight->getCols()), static_cast<unsigned char>(mLeft->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400599 }
600 else if (!mLeft->isMatrix() && !mRight->isMatrix())
601 {
602 if (mLeft->isVector() && mRight->isVector())
603 {
604 // leave as component product
605 }
606 else if (mLeft->isVector() || mRight->isVector())
607 {
608 mOp = EOpVectorTimesScalar;
609 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700610 static_cast<unsigned char>(nominalSize), 1));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400611 }
612 }
613 else
614 {
615 infoSink.info.message(EPrefixInternalError, getLine(),
616 "Missing elses");
617 return false;
618 }
619
620 if (!ValidateMultiplication(mOp, mLeft->getType(), mRight->getType()))
621 {
622 return false;
623 }
624 break;
625
626 case EOpMulAssign:
627 if (!mLeft->isMatrix() && mRight->isMatrix())
628 {
629 if (mLeft->isVector())
630 {
631 mOp = EOpVectorTimesMatrixAssign;
632 }
633 else
634 {
635 return false;
636 }
637 }
638 else if (mLeft->isMatrix() && !mRight->isMatrix())
639 {
640 if (mRight->isVector())
641 {
642 return false;
643 }
644 else
645 {
646 mOp = EOpMatrixTimesScalarAssign;
647 }
648 }
649 else if (mLeft->isMatrix() && mRight->isMatrix())
650 {
651 mOp = EOpMatrixTimesMatrixAssign;
652 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700653 static_cast<unsigned char>(mRight->getCols()), static_cast<unsigned char>(mLeft->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400654 }
655 else if (!mLeft->isMatrix() && !mRight->isMatrix())
656 {
657 if (mLeft->isVector() && mRight->isVector())
658 {
659 // leave as component product
660 }
661 else if (mLeft->isVector() || mRight->isVector())
662 {
663 if (!mLeft->isVector())
664 return false;
665 mOp = EOpVectorTimesScalarAssign;
666 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700667 static_cast<unsigned char>(mLeft->getNominalSize()), 1));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400668 }
669 }
670 else
671 {
672 infoSink.info.message(EPrefixInternalError, getLine(),
673 "Missing elses");
674 return false;
675 }
676
677 if (!ValidateMultiplication(mOp, mLeft->getType(), mRight->getType()))
678 {
679 return false;
680 }
681 break;
682
683 case EOpAssign:
684 case EOpInitialize:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200685 // No more additional checks are needed.
686 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
687 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
688 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400689 case EOpAdd:
690 case EOpSub:
691 case EOpDiv:
Olli Etuahoff805cc2015-02-13 10:59:34 +0200692 case EOpIMod:
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200693 case EOpBitShiftLeft:
694 case EOpBitShiftRight:
695 case EOpBitwiseAnd:
696 case EOpBitwiseXor:
697 case EOpBitwiseOr:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400698 case EOpAddAssign:
699 case EOpSubAssign:
700 case EOpDivAssign:
Olli Etuahoff805cc2015-02-13 10:59:34 +0200701 case EOpIModAssign:
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200702 case EOpBitShiftLeftAssign:
703 case EOpBitShiftRightAssign:
704 case EOpBitwiseAndAssign:
705 case EOpBitwiseXorAssign:
706 case EOpBitwiseOrAssign:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400707 if ((mLeft->isMatrix() && mRight->isVector()) ||
708 (mLeft->isVector() && mRight->isMatrix()))
709 {
710 return false;
711 }
712
713 // Are the sizes compatible?
714 if (mLeft->getNominalSize() != mRight->getNominalSize() ||
715 mLeft->getSecondarySize() != mRight->getSecondarySize())
716 {
Olli Etuaho6c850472014-12-02 16:23:17 +0200717 // If the nominal sizes of operands do not match:
718 // One of them must be a scalar.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400719 if (!mLeft->isScalar() && !mRight->isScalar())
720 return false;
721
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200722 // In the case of compound assignment other than multiply-assign,
723 // the right side needs to be a scalar. Otherwise a vector/matrix
724 // would be assigned to a scalar. A scalar can't be shifted by a
725 // vector either.
Olli Etuaho6c850472014-12-02 16:23:17 +0200726 if (!mRight->isScalar() &&
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200727 (isAssignment() ||
728 mOp == EOpBitShiftLeft ||
729 mOp == EOpBitShiftRight))
Olli Etuaho6c850472014-12-02 16:23:17 +0200730 return false;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400731 }
732
733 {
734 const int secondarySize = std::max(
735 mLeft->getSecondarySize(), mRight->getSecondarySize());
736 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700737 static_cast<unsigned char>(nominalSize), static_cast<unsigned char>(secondarySize)));
Olli Etuahoe79904c2015-03-18 16:56:42 +0200738 if (mLeft->isArray())
739 {
740 ASSERT(mLeft->getArraySize() == mRight->getArraySize());
741 mType.setArraySize(mLeft->getArraySize());
742 }
Jamie Madillb1a85f42014-08-19 15:23:24 -0400743 }
744 break;
745
746 case EOpEqual:
747 case EOpNotEqual:
748 case EOpLessThan:
749 case EOpGreaterThan:
750 case EOpLessThanEqual:
751 case EOpGreaterThanEqual:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200752 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
753 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400754 setType(TType(EbtBool, EbpUndefined));
755 break;
756
757 default:
758 return false;
759 }
760 return true;
761}
762
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300763TIntermTyped *TIntermBinary::fold(TInfoSink &infoSink)
764{
765 TIntermConstantUnion *leftConstant = mLeft->getAsConstantUnion();
766 TIntermConstantUnion *rightConstant = mRight->getAsConstantUnion();
767 if (leftConstant == nullptr || rightConstant == nullptr)
768 {
769 return nullptr;
770 }
771 TConstantUnion *constArray = leftConstant->foldBinary(mOp, rightConstant, infoSink);
Olli Etuahob43846e2015-06-02 18:18:57 +0300772 return CreateFoldedNode(constArray, this);
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300773}
774
Olli Etuaho95310b02015-06-02 17:43:38 +0300775TIntermTyped *TIntermUnary::fold(TInfoSink &infoSink)
776{
777 TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
778 if (operandConstant == nullptr)
779 {
780 return nullptr;
781 }
782 TConstantUnion *constArray = operandConstant->foldUnary(mOp, infoSink);
Olli Etuahob43846e2015-06-02 18:18:57 +0300783 return CreateFoldedNode(constArray, this);
784}
785
786TIntermTyped *TIntermAggregate::fold(TInfoSink &infoSink)
787{
788 // Make sure that all params are constant before actual constant folding.
789 for (auto *param : *getSequence())
Olli Etuaho95310b02015-06-02 17:43:38 +0300790 {
Olli Etuahob43846e2015-06-02 18:18:57 +0300791 if (param->getAsConstantUnion() == nullptr)
792 {
793 return nullptr;
794 }
Olli Etuaho95310b02015-06-02 17:43:38 +0300795 }
Olli Etuahob43846e2015-06-02 18:18:57 +0300796 TConstantUnion *constArray = TIntermConstantUnion::FoldAggregateBuiltIn(this, infoSink);
797 return CreateFoldedNode(constArray, this);
Olli Etuaho95310b02015-06-02 17:43:38 +0300798}
799
Jamie Madillb1a85f42014-08-19 15:23:24 -0400800//
801// The fold functions see if an operation on a constant can be done in place,
802// without generating run-time code.
803//
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300804// Returns the constant value to keep using or nullptr.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400805//
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300806TConstantUnion *TIntermConstantUnion::foldBinary(TOperator op, TIntermConstantUnion *rightNode, TInfoSink &infoSink)
807{
808 TConstantUnion *leftArray = getUnionArrayPointer();
809 TConstantUnion *rightArray = rightNode->getUnionArrayPointer();
810
811 if (!leftArray)
812 return nullptr;
813 if (!rightArray)
814 return nullptr;
815
816 size_t objectSize = getType().getObjectSize();
817
818 // for a case like float f = vec4(2, 3, 4, 5) + 1.2;
819 if (rightNode->getType().getObjectSize() == 1 && objectSize > 1)
820 {
821 rightArray = Vectorize(*rightNode->getUnionArrayPointer(), objectSize);
822 }
823 else if (rightNode->getType().getObjectSize() > 1 && objectSize == 1)
824 {
825 // for a case like float f = 1.2 + vec4(2, 3, 4, 5);
826 leftArray = Vectorize(*getUnionArrayPointer(), rightNode->getType().getObjectSize());
827 objectSize = rightNode->getType().getObjectSize();
828 }
829
830 TConstantUnion *resultArray = nullptr;
831
832 switch(op)
833 {
834 case EOpAdd:
835 resultArray = new TConstantUnion[objectSize];
836 for (size_t i = 0; i < objectSize; i++)
837 resultArray[i] = leftArray[i] + rightArray[i];
838 break;
839 case EOpSub:
840 resultArray = new TConstantUnion[objectSize];
841 for (size_t i = 0; i < objectSize; i++)
842 resultArray[i] = leftArray[i] - rightArray[i];
843 break;
844
845 case EOpMul:
846 case EOpVectorTimesScalar:
847 case EOpMatrixTimesScalar:
848 resultArray = new TConstantUnion[objectSize];
849 for (size_t i = 0; i < objectSize; i++)
850 resultArray[i] = leftArray[i] * rightArray[i];
851 break;
852
853 case EOpMatrixTimesMatrix:
854 {
855 if (getType().getBasicType() != EbtFloat ||
856 rightNode->getBasicType() != EbtFloat)
857 {
858 infoSink.info.message(
859 EPrefixInternalError, getLine(),
860 "Constant Folding cannot be done for matrix multiply");
861 return nullptr;
862 }
863
864 const int leftCols = getCols();
865 const int leftRows = getRows();
866 const int rightCols = rightNode->getType().getCols();
867 const int rightRows = rightNode->getType().getRows();
868 const int resultCols = rightCols;
869 const int resultRows = leftRows;
870
871 resultArray = new TConstantUnion[resultCols * resultRows];
872 for (int row = 0; row < resultRows; row++)
873 {
874 for (int column = 0; column < resultCols; column++)
875 {
876 resultArray[resultRows * column + row].setFConst(0.0f);
877 for (int i = 0; i < leftCols; i++)
878 {
879 resultArray[resultRows * column + row].setFConst(
880 resultArray[resultRows * column + row].getFConst() +
881 leftArray[i * leftRows + row].getFConst() *
882 rightArray[column * rightRows + i].getFConst());
883 }
884 }
885 }
886 }
887 break;
888
889 case EOpDiv:
890 case EOpIMod:
891 {
892 resultArray = new TConstantUnion[objectSize];
893 for (size_t i = 0; i < objectSize; i++)
894 {
895 switch (getType().getBasicType())
896 {
897 case EbtFloat:
898 if (rightArray[i] == 0.0f)
899 {
900 infoSink.info.message(EPrefixWarning, getLine(),
901 "Divide by zero error during constant folding");
902 resultArray[i].setFConst(leftArray[i].getFConst() < 0 ? -FLT_MAX : FLT_MAX);
903 }
904 else
905 {
906 ASSERT(op == EOpDiv);
907 resultArray[i].setFConst(leftArray[i].getFConst() / rightArray[i].getFConst());
908 }
909 break;
910
911 case EbtInt:
912 if (rightArray[i] == 0)
913 {
914 infoSink.info.message(EPrefixWarning, getLine(),
915 "Divide by zero error during constant folding");
916 resultArray[i].setIConst(INT_MAX);
917 }
918 else
919 {
920 if (op == EOpDiv)
921 {
922 resultArray[i].setIConst(leftArray[i].getIConst() / rightArray[i].getIConst());
923 }
924 else
925 {
926 ASSERT(op == EOpIMod);
927 resultArray[i].setIConst(leftArray[i].getIConst() % rightArray[i].getIConst());
928 }
929 }
930 break;
931
932 case EbtUInt:
933 if (rightArray[i] == 0)
934 {
935 infoSink.info.message(EPrefixWarning, getLine(),
936 "Divide by zero error during constant folding");
937 resultArray[i].setUConst(UINT_MAX);
938 }
939 else
940 {
941 if (op == EOpDiv)
942 {
943 resultArray[i].setUConst(leftArray[i].getUConst() / rightArray[i].getUConst());
944 }
945 else
946 {
947 ASSERT(op == EOpIMod);
948 resultArray[i].setUConst(leftArray[i].getUConst() % rightArray[i].getUConst());
949 }
950 }
951 break;
952
953 default:
954 infoSink.info.message(EPrefixInternalError, getLine(),
955 "Constant folding cannot be done for \"/\"");
956 return nullptr;
957 }
958 }
959 }
960 break;
961
962 case EOpMatrixTimesVector:
963 {
964 if (rightNode->getBasicType() != EbtFloat)
965 {
966 infoSink.info.message(EPrefixInternalError, getLine(),
967 "Constant Folding cannot be done for matrix times vector");
968 return nullptr;
969 }
970
971 const int matrixCols = getCols();
972 const int matrixRows = getRows();
973
974 resultArray = new TConstantUnion[matrixRows];
975
976 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
977 {
978 resultArray[matrixRow].setFConst(0.0f);
979 for (int col = 0; col < matrixCols; col++)
980 {
981 resultArray[matrixRow].setFConst(resultArray[matrixRow].getFConst() +
982 leftArray[col * matrixRows + matrixRow].getFConst() *
983 rightArray[col].getFConst());
984 }
985 }
986 }
987 break;
988
989 case EOpVectorTimesMatrix:
990 {
991 if (getType().getBasicType() != EbtFloat)
992 {
993 infoSink.info.message(EPrefixInternalError, getLine(),
994 "Constant Folding cannot be done for vector times matrix");
995 return nullptr;
996 }
997
998 const int matrixCols = rightNode->getType().getCols();
999 const int matrixRows = rightNode->getType().getRows();
1000
1001 resultArray = new TConstantUnion[matrixCols];
1002
1003 for (int matrixCol = 0; matrixCol < matrixCols; matrixCol++)
1004 {
1005 resultArray[matrixCol].setFConst(0.0f);
1006 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1007 {
1008 resultArray[matrixCol].setFConst(resultArray[matrixCol].getFConst() +
1009 leftArray[matrixRow].getFConst() *
1010 rightArray[matrixCol * matrixRows + matrixRow].getFConst());
1011 }
1012 }
1013 }
1014 break;
1015
1016 case EOpLogicalAnd:
1017 {
1018 resultArray = new TConstantUnion[objectSize];
1019 for (size_t i = 0; i < objectSize; i++)
1020 {
1021 resultArray[i] = leftArray[i] && rightArray[i];
1022 }
1023 }
1024 break;
1025
1026 case EOpLogicalOr:
1027 {
1028 resultArray = new TConstantUnion[objectSize];
1029 for (size_t i = 0; i < objectSize; i++)
1030 {
1031 resultArray[i] = leftArray[i] || rightArray[i];
1032 }
1033 }
1034 break;
1035
1036 case EOpLogicalXor:
1037 {
1038 resultArray = new TConstantUnion[objectSize];
1039 for (size_t i = 0; i < objectSize; i++)
1040 {
1041 switch (getType().getBasicType())
1042 {
1043 case EbtBool:
1044 resultArray[i].setBConst(leftArray[i] != rightArray[i]);
1045 break;
1046 default:
1047 UNREACHABLE();
1048 break;
1049 }
1050 }
1051 }
1052 break;
1053
1054 case EOpBitwiseAnd:
1055 resultArray = new TConstantUnion[objectSize];
1056 for (size_t i = 0; i < objectSize; i++)
1057 resultArray[i] = leftArray[i] & rightArray[i];
1058 break;
1059 case EOpBitwiseXor:
1060 resultArray = new TConstantUnion[objectSize];
1061 for (size_t i = 0; i < objectSize; i++)
1062 resultArray[i] = leftArray[i] ^ rightArray[i];
1063 break;
1064 case EOpBitwiseOr:
1065 resultArray = new TConstantUnion[objectSize];
1066 for (size_t i = 0; i < objectSize; i++)
1067 resultArray[i] = leftArray[i] | rightArray[i];
1068 break;
1069 case EOpBitShiftLeft:
1070 resultArray = new TConstantUnion[objectSize];
1071 for (size_t i = 0; i < objectSize; i++)
1072 resultArray[i] = leftArray[i] << rightArray[i];
1073 break;
1074 case EOpBitShiftRight:
1075 resultArray = new TConstantUnion[objectSize];
1076 for (size_t i = 0; i < objectSize; i++)
1077 resultArray[i] = leftArray[i] >> rightArray[i];
1078 break;
1079
1080 case EOpLessThan:
1081 ASSERT(objectSize == 1);
1082 resultArray = new TConstantUnion[1];
1083 resultArray->setBConst(*leftArray < *rightArray);
1084 break;
1085
1086 case EOpGreaterThan:
1087 ASSERT(objectSize == 1);
1088 resultArray = new TConstantUnion[1];
1089 resultArray->setBConst(*leftArray > *rightArray);
1090 break;
1091
1092 case EOpLessThanEqual:
1093 ASSERT(objectSize == 1);
1094 resultArray = new TConstantUnion[1];
1095 resultArray->setBConst(!(*leftArray > *rightArray));
1096 break;
1097
1098 case EOpGreaterThanEqual:
1099 ASSERT(objectSize == 1);
1100 resultArray = new TConstantUnion[1];
1101 resultArray->setBConst(!(*leftArray < *rightArray));
1102 break;
1103
1104 case EOpEqual:
1105 case EOpNotEqual:
1106 {
1107 resultArray = new TConstantUnion[1];
1108 bool equal = true;
1109 if (getType().getBasicType() == EbtStruct)
1110 {
1111 equal = CompareStructure(getType(), rightArray, leftArray);
1112 }
1113 else
1114 {
1115 for (size_t i = 0; i < objectSize; i++)
1116 {
1117 if (leftArray[i] != rightArray[i])
1118 {
1119 equal = false;
1120 break; // break out of for loop
1121 }
1122 }
1123 }
1124 if (op == EOpEqual)
1125 {
1126 resultArray->setBConst(equal);
1127 }
1128 else
1129 {
1130 resultArray->setBConst(!equal);
1131 }
1132 }
1133 break;
1134
1135 default:
1136 infoSink.info.message(
1137 EPrefixInternalError, getLine(),
1138 "Invalid operator for constant folding");
1139 return nullptr;
1140 }
1141 return resultArray;
1142}
1143
1144//
1145// The fold functions see if an operation on a constant can be done in place,
1146// without generating run-time code.
1147//
Olli Etuaho95310b02015-06-02 17:43:38 +03001148// Returns the constant value to keep using or nullptr.
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001149//
Olli Etuaho95310b02015-06-02 17:43:38 +03001150TConstantUnion *TIntermConstantUnion::foldUnary(TOperator op, TInfoSink &infoSink)
Jamie Madillb1a85f42014-08-19 15:23:24 -04001151{
Olli Etuaho95310b02015-06-02 17:43:38 +03001152 TConstantUnion *operandArray = getUnionArrayPointer();
Jamie Madillb1a85f42014-08-19 15:23:24 -04001153
Olli Etuaho95310b02015-06-02 17:43:38 +03001154 if (!operandArray)
Arun Patolefddc2112015-04-22 13:28:10 +05301155 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001156
1157 size_t objectSize = getType().getObjectSize();
1158
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001159 if (op == EOpAny || op == EOpAll || op == EOpLength)
Arun Patole9d0b1f92015-05-20 14:27:17 +05301160 {
Olli Etuaho95310b02015-06-02 17:43:38 +03001161 // Do operations where the return type has a different number of components compared to the operand type.
1162 TConstantUnion *resultArray = nullptr;
Arun Patole9d0b1f92015-05-20 14:27:17 +05301163
Arun Patole1155ddd2015-06-05 18:04:36 +05301164 switch (op)
Arun Patole9d0b1f92015-05-20 14:27:17 +05301165 {
Arun Patole1155ddd2015-06-05 18:04:36 +05301166 case EOpAny:
Arun Patole9d0b1f92015-05-20 14:27:17 +05301167 if (getType().getBasicType() == EbtBool)
1168 {
Olli Etuaho95310b02015-06-02 17:43:38 +03001169 resultArray = new TConstantUnion();
1170 resultArray->setBConst(false);
Arun Patole9d0b1f92015-05-20 14:27:17 +05301171 for (size_t i = 0; i < objectSize; i++)
1172 {
Olli Etuaho95310b02015-06-02 17:43:38 +03001173 if (operandArray[i].getBConst())
Arun Patole9d0b1f92015-05-20 14:27:17 +05301174 {
Olli Etuaho95310b02015-06-02 17:43:38 +03001175 resultArray->setBConst(true);
Arun Patole9d0b1f92015-05-20 14:27:17 +05301176 break;
1177 }
1178 }
Arun Patole1155ddd2015-06-05 18:04:36 +05301179 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05301180 }
1181 else
1182 {
Arun Patole1155ddd2015-06-05 18:04:36 +05301183 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
Arun Patole9d0b1f92015-05-20 14:27:17 +05301184 return nullptr;
1185 }
Arun Patole1155ddd2015-06-05 18:04:36 +05301186
1187 case EOpAll:
Arun Patole9d0b1f92015-05-20 14:27:17 +05301188 if (getType().getBasicType() == EbtBool)
1189 {
Olli Etuaho95310b02015-06-02 17:43:38 +03001190 resultArray = new TConstantUnion();
1191 resultArray->setBConst(true);
Arun Patole9d0b1f92015-05-20 14:27:17 +05301192 for (size_t i = 0; i < objectSize; i++)
1193 {
Olli Etuaho95310b02015-06-02 17:43:38 +03001194 if (!operandArray[i].getBConst())
Arun Patole9d0b1f92015-05-20 14:27:17 +05301195 {
Olli Etuaho95310b02015-06-02 17:43:38 +03001196 resultArray->setBConst(false);
Arun Patole9d0b1f92015-05-20 14:27:17 +05301197 break;
1198 }
1199 }
Arun Patole1155ddd2015-06-05 18:04:36 +05301200 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05301201 }
1202 else
1203 {
Arun Patole1155ddd2015-06-05 18:04:36 +05301204 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
Arun Patole9d0b1f92015-05-20 14:27:17 +05301205 return nullptr;
1206 }
Arun Patole1155ddd2015-06-05 18:04:36 +05301207
1208 case EOpLength:
1209 if (getType().getBasicType() == EbtFloat)
1210 {
Olli Etuaho95310b02015-06-02 17:43:38 +03001211 resultArray = new TConstantUnion();
1212 resultArray->setFConst(VectorLength(operandArray, objectSize));
Arun Patole1155ddd2015-06-05 18:04:36 +05301213 break;
1214 }
1215 else
1216 {
1217 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1218 return nullptr;
1219 }
1220
1221 default:
1222 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05301223 }
Arun Patole1155ddd2015-06-05 18:04:36 +05301224
Olli Etuaho95310b02015-06-02 17:43:38 +03001225 return resultArray;
Arun Patole9d0b1f92015-05-20 14:27:17 +05301226 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04001227 else
1228 {
1229 //
Arun Patole9d0b1f92015-05-20 14:27:17 +05301230 // Do unary operations where the return type is the same as operand type.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001231 //
Olli Etuaho95310b02015-06-02 17:43:38 +03001232 TConstantUnion *resultArray = new TConstantUnion[objectSize];
Jamie Madillb1a85f42014-08-19 15:23:24 -04001233 for (size_t i = 0; i < objectSize; i++)
1234 {
1235 switch(op)
1236 {
1237 case EOpNegative:
1238 switch (getType().getBasicType())
1239 {
1240 case EbtFloat:
Olli Etuaho95310b02015-06-02 17:43:38 +03001241 resultArray[i].setFConst(-operandArray[i].getFConst());
Jamie Madillb1a85f42014-08-19 15:23:24 -04001242 break;
1243 case EbtInt:
Olli Etuaho95310b02015-06-02 17:43:38 +03001244 resultArray[i].setIConst(-operandArray[i].getIConst());
Jamie Madillb1a85f42014-08-19 15:23:24 -04001245 break;
1246 case EbtUInt:
Olli Etuaho95310b02015-06-02 17:43:38 +03001247 resultArray[i].setUConst(static_cast<unsigned int>(
1248 -static_cast<int>(operandArray[i].getUConst())));
Jamie Madillb1a85f42014-08-19 15:23:24 -04001249 break;
1250 default:
1251 infoSink.info.message(
1252 EPrefixInternalError, getLine(),
1253 "Unary operation not folded into constant");
Arun Patolefddc2112015-04-22 13:28:10 +05301254 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001255 }
1256 break;
1257
Zhenyao Mode1e00e2014-10-09 16:55:32 -07001258 case EOpPositive:
1259 switch (getType().getBasicType())
1260 {
1261 case EbtFloat:
Olli Etuaho95310b02015-06-02 17:43:38 +03001262 resultArray[i].setFConst(operandArray[i].getFConst());
Zhenyao Mode1e00e2014-10-09 16:55:32 -07001263 break;
1264 case EbtInt:
Olli Etuaho95310b02015-06-02 17:43:38 +03001265 resultArray[i].setIConst(operandArray[i].getIConst());
Zhenyao Mode1e00e2014-10-09 16:55:32 -07001266 break;
1267 case EbtUInt:
Olli Etuaho95310b02015-06-02 17:43:38 +03001268 resultArray[i].setUConst(static_cast<unsigned int>(
1269 static_cast<int>(operandArray[i].getUConst())));
Zhenyao Mode1e00e2014-10-09 16:55:32 -07001270 break;
1271 default:
1272 infoSink.info.message(
1273 EPrefixInternalError, getLine(),
1274 "Unary operation not folded into constant");
Arun Patolefddc2112015-04-22 13:28:10 +05301275 return nullptr;
Zhenyao Mode1e00e2014-10-09 16:55:32 -07001276 }
1277 break;
1278
Jamie Madillb1a85f42014-08-19 15:23:24 -04001279 case EOpLogicalNot:
1280 // this code is written for possible future use,
1281 // will not get executed currently
1282 switch (getType().getBasicType())
1283 {
1284 case EbtBool:
Olli Etuaho95310b02015-06-02 17:43:38 +03001285 resultArray[i].setBConst(!operandArray[i].getBConst());
Jamie Madillb1a85f42014-08-19 15:23:24 -04001286 break;
1287 default:
1288 infoSink.info.message(
1289 EPrefixInternalError, getLine(),
1290 "Unary operation not folded into constant");
Arun Patolefddc2112015-04-22 13:28:10 +05301291 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001292 }
1293 break;
1294
Olli Etuaho31b5fc62015-01-16 12:13:36 +02001295 case EOpBitwiseNot:
1296 switch (getType().getBasicType())
1297 {
1298 case EbtInt:
Olli Etuaho95310b02015-06-02 17:43:38 +03001299 resultArray[i].setIConst(~operandArray[i].getIConst());
Olli Etuaho31b5fc62015-01-16 12:13:36 +02001300 break;
1301 case EbtUInt:
Olli Etuaho95310b02015-06-02 17:43:38 +03001302 resultArray[i].setUConst(~operandArray[i].getUConst());
Olli Etuaho31b5fc62015-01-16 12:13:36 +02001303 break;
1304 default:
1305 infoSink.info.message(
1306 EPrefixInternalError, getLine(),
1307 "Unary operation not folded into constant");
Arun Patolefddc2112015-04-22 13:28:10 +05301308 return nullptr;
Olli Etuaho31b5fc62015-01-16 12:13:36 +02001309 }
1310 break;
1311
Arun Patole9dea48f2015-04-02 11:45:09 +05301312 case EOpRadians:
1313 if (getType().getBasicType() == EbtFloat)
1314 {
Olli Etuaho95310b02015-06-02 17:43:38 +03001315 resultArray[i].setFConst(kDegreesToRadiansMultiplier * operandArray[i].getFConst());
Arun Patole9dea48f2015-04-02 11:45:09 +05301316 break;
1317 }
1318 infoSink.info.message(
1319 EPrefixInternalError, getLine(),
1320 "Unary operation not folded into constant");
1321 return nullptr;
1322
1323 case EOpDegrees:
1324 if (getType().getBasicType() == EbtFloat)
1325 {
Olli Etuaho95310b02015-06-02 17:43:38 +03001326 resultArray[i].setFConst(kRadiansToDegreesMultiplier * operandArray[i].getFConst());
Arun Patole9dea48f2015-04-02 11:45:09 +05301327 break;
1328 }
1329 infoSink.info.message(
1330 EPrefixInternalError, getLine(),
1331 "Unary operation not folded into constant");
1332 return nullptr;
1333
1334 case EOpSin:
Olli Etuaho95310b02015-06-02 17:43:38 +03001335 if (!foldFloatTypeUnary(operandArray[i], &sinf, infoSink, &resultArray[i]))
Arun Patole9dea48f2015-04-02 11:45:09 +05301336 return nullptr;
1337 break;
1338
1339 case EOpCos:
Olli Etuaho95310b02015-06-02 17:43:38 +03001340 if (!foldFloatTypeUnary(operandArray[i], &cosf, infoSink, &resultArray[i]))
Arun Patole9dea48f2015-04-02 11:45:09 +05301341 return nullptr;
1342 break;
1343
1344 case EOpTan:
Olli Etuaho95310b02015-06-02 17:43:38 +03001345 if (!foldFloatTypeUnary(operandArray[i], &tanf, infoSink, &resultArray[i]))
Arun Patole9dea48f2015-04-02 11:45:09 +05301346 return nullptr;
1347 break;
1348
1349 case EOpAsin:
1350 // For asin(x), results are undefined if |x| > 1, we are choosing to set result to 0.
Olli Etuaho95310b02015-06-02 17:43:38 +03001351 if (getType().getBasicType() == EbtFloat && fabsf(operandArray[i].getFConst()) > 1.0f)
1352 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1353 else if (!foldFloatTypeUnary(operandArray[i], &asinf, infoSink, &resultArray[i]))
Arun Patole9dea48f2015-04-02 11:45:09 +05301354 return nullptr;
1355 break;
1356
1357 case EOpAcos:
1358 // For acos(x), results are undefined if |x| > 1, we are choosing to set result to 0.
Olli Etuaho95310b02015-06-02 17:43:38 +03001359 if (getType().getBasicType() == EbtFloat && fabsf(operandArray[i].getFConst()) > 1.0f)
1360 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1361 else if (!foldFloatTypeUnary(operandArray[i], &acosf, infoSink, &resultArray[i]))
Arun Patole9dea48f2015-04-02 11:45:09 +05301362 return nullptr;
1363 break;
1364
1365 case EOpAtan:
Olli Etuaho95310b02015-06-02 17:43:38 +03001366 if (!foldFloatTypeUnary(operandArray[i], &atanf, infoSink, &resultArray[i]))
Arun Patole9dea48f2015-04-02 11:45:09 +05301367 return nullptr;
1368 break;
1369
1370 case EOpSinh:
Olli Etuaho95310b02015-06-02 17:43:38 +03001371 if (!foldFloatTypeUnary(operandArray[i], &sinhf, infoSink, &resultArray[i]))
Arun Patole9dea48f2015-04-02 11:45:09 +05301372 return nullptr;
1373 break;
1374
1375 case EOpCosh:
Olli Etuaho95310b02015-06-02 17:43:38 +03001376 if (!foldFloatTypeUnary(operandArray[i], &coshf, infoSink, &resultArray[i]))
Arun Patole9dea48f2015-04-02 11:45:09 +05301377 return nullptr;
1378 break;
1379
1380 case EOpTanh:
Olli Etuaho95310b02015-06-02 17:43:38 +03001381 if (!foldFloatTypeUnary(operandArray[i], &tanhf, infoSink, &resultArray[i]))
Arun Patole9dea48f2015-04-02 11:45:09 +05301382 return nullptr;
1383 break;
1384
1385 case EOpAsinh:
Olli Etuaho95310b02015-06-02 17:43:38 +03001386 if (!foldFloatTypeUnary(operandArray[i], &asinhf, infoSink, &resultArray[i]))
Arun Patole9dea48f2015-04-02 11:45:09 +05301387 return nullptr;
1388 break;
1389
1390 case EOpAcosh:
1391 // For acosh(x), results are undefined if x < 1, we are choosing to set result to 0.
Olli Etuaho95310b02015-06-02 17:43:38 +03001392 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() < 1.0f)
1393 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1394 else if (!foldFloatTypeUnary(operandArray[i], &acoshf, infoSink, &resultArray[i]))
Arun Patole9dea48f2015-04-02 11:45:09 +05301395 return nullptr;
1396 break;
1397
1398 case EOpAtanh:
1399 // For atanh(x), results are undefined if |x| >= 1, we are choosing to set result to 0.
Olli Etuaho95310b02015-06-02 17:43:38 +03001400 if (getType().getBasicType() == EbtFloat && fabsf(operandArray[i].getFConst()) >= 1.0f)
1401 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1402 else if (!foldFloatTypeUnary(operandArray[i], &atanhf, infoSink, &resultArray[i]))
Arun Patole9dea48f2015-04-02 11:45:09 +05301403 return nullptr;
1404 break;
1405
Arun Patole97dc22e2015-04-06 17:35:38 +05301406 case EOpAbs:
1407 switch (getType().getBasicType())
1408 {
1409 case EbtFloat:
Olli Etuaho95310b02015-06-02 17:43:38 +03001410 resultArray[i].setFConst(fabsf(operandArray[i].getFConst()));
Arun Patole97dc22e2015-04-06 17:35:38 +05301411 break;
1412 case EbtInt:
Olli Etuaho95310b02015-06-02 17:43:38 +03001413 resultArray[i].setIConst(abs(operandArray[i].getIConst()));
Arun Patole97dc22e2015-04-06 17:35:38 +05301414 break;
1415 default:
1416 infoSink.info.message(
1417 EPrefixInternalError, getLine(),
1418 "Unary operation not folded into constant");
1419 return nullptr;
1420 }
1421 break;
1422
1423 case EOpSign:
1424 switch (getType().getBasicType())
1425 {
1426 case EbtFloat:
1427 {
Olli Etuaho95310b02015-06-02 17:43:38 +03001428 float fConst = operandArray[i].getFConst();
Arun Patole97dc22e2015-04-06 17:35:38 +05301429 float fResult = 0.0f;
1430 if (fConst > 0.0f)
1431 fResult = 1.0f;
1432 else if (fConst < 0.0f)
1433 fResult = -1.0f;
Olli Etuaho95310b02015-06-02 17:43:38 +03001434 resultArray[i].setFConst(fResult);
Arun Patole97dc22e2015-04-06 17:35:38 +05301435 }
1436 break;
1437 case EbtInt:
1438 {
Olli Etuaho95310b02015-06-02 17:43:38 +03001439 int iConst = operandArray[i].getIConst();
Arun Patole97dc22e2015-04-06 17:35:38 +05301440 int iResult = 0;
1441 if (iConst > 0)
1442 iResult = 1;
1443 else if (iConst < 0)
1444 iResult = -1;
Olli Etuaho95310b02015-06-02 17:43:38 +03001445 resultArray[i].setIConst(iResult);
Arun Patole97dc22e2015-04-06 17:35:38 +05301446 }
1447 break;
1448 default:
1449 infoSink.info.message(
1450 EPrefixInternalError, getLine(),
1451 "Unary operation not folded into constant");
1452 return nullptr;
1453 }
1454 break;
1455
1456 case EOpFloor:
Olli Etuaho95310b02015-06-02 17:43:38 +03001457 if (!foldFloatTypeUnary(operandArray[i], &floorf, infoSink, &resultArray[i]))
Arun Patole97dc22e2015-04-06 17:35:38 +05301458 return nullptr;
1459 break;
1460
1461 case EOpTrunc:
Olli Etuaho95310b02015-06-02 17:43:38 +03001462 if (!foldFloatTypeUnary(operandArray[i], &truncf, infoSink, &resultArray[i]))
Arun Patole97dc22e2015-04-06 17:35:38 +05301463 return nullptr;
1464 break;
1465
1466 case EOpRound:
Olli Etuaho95310b02015-06-02 17:43:38 +03001467 if (!foldFloatTypeUnary(operandArray[i], &roundf, infoSink, &resultArray[i]))
Arun Patole97dc22e2015-04-06 17:35:38 +05301468 return nullptr;
1469 break;
1470
1471 case EOpRoundEven:
1472 if (getType().getBasicType() == EbtFloat)
1473 {
Olli Etuaho95310b02015-06-02 17:43:38 +03001474 float x = operandArray[i].getFConst();
Arun Patole97dc22e2015-04-06 17:35:38 +05301475 float result;
1476 float fractPart = modff(x, &result);
1477 if (fabsf(fractPart) == 0.5f)
1478 result = 2.0f * roundf(x / 2.0f);
1479 else
1480 result = roundf(x);
Olli Etuaho95310b02015-06-02 17:43:38 +03001481 resultArray[i].setFConst(result);
Arun Patole97dc22e2015-04-06 17:35:38 +05301482 break;
1483 }
1484 infoSink.info.message(
1485 EPrefixInternalError, getLine(),
1486 "Unary operation not folded into constant");
1487 return nullptr;
1488
1489 case EOpCeil:
Olli Etuaho95310b02015-06-02 17:43:38 +03001490 if (!foldFloatTypeUnary(operandArray[i], &ceilf, infoSink, &resultArray[i]))
Arun Patole97dc22e2015-04-06 17:35:38 +05301491 return nullptr;
1492 break;
1493
1494 case EOpFract:
1495 if (getType().getBasicType() == EbtFloat)
1496 {
Olli Etuaho95310b02015-06-02 17:43:38 +03001497 float x = operandArray[i].getFConst();
1498 resultArray[i].setFConst(x - floorf(x));
Arun Patole97dc22e2015-04-06 17:35:38 +05301499 break;
1500 }
1501 infoSink.info.message(
1502 EPrefixInternalError, getLine(),
1503 "Unary operation not folded into constant");
1504 return nullptr;
1505
Arun Patole28eb65e2015-04-06 17:29:48 +05301506 case EOpExp:
Olli Etuaho95310b02015-06-02 17:43:38 +03001507 if (!foldFloatTypeUnary(operandArray[i], &expf, infoSink, &resultArray[i]))
Arun Patole28eb65e2015-04-06 17:29:48 +05301508 return nullptr;
1509 break;
1510
1511 case EOpLog:
1512 // For log(x), results are undefined if x <= 0, we are choosing to set result to 0.
Olli Etuaho95310b02015-06-02 17:43:38 +03001513 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() <= 0.0f)
1514 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1515 else if (!foldFloatTypeUnary(operandArray[i], &logf, infoSink, &resultArray[i]))
Arun Patole28eb65e2015-04-06 17:29:48 +05301516 return nullptr;
1517 break;
1518
1519 case EOpExp2:
Olli Etuaho95310b02015-06-02 17:43:38 +03001520 if (!foldFloatTypeUnary(operandArray[i], &exp2f, infoSink, &resultArray[i]))
Arun Patole28eb65e2015-04-06 17:29:48 +05301521 return nullptr;
1522 break;
1523
1524 case EOpLog2:
1525 // For log2(x), results are undefined if x <= 0, we are choosing to set result to 0.
1526 // 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 +03001527 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() <= 0.0f)
1528 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1529 else if (!foldFloatTypeUnary(operandArray[i], &logf, infoSink, &resultArray[i]))
Arun Patole28eb65e2015-04-06 17:29:48 +05301530 return nullptr;
1531 else
Olli Etuaho95310b02015-06-02 17:43:38 +03001532 resultArray[i].setFConst(resultArray[i].getFConst() / logf(2.0f));
Arun Patole28eb65e2015-04-06 17:29:48 +05301533 break;
1534
1535 case EOpSqrt:
1536 // For sqrt(x), results are undefined if x < 0, we are choosing to set result to 0.
Olli Etuaho95310b02015-06-02 17:43:38 +03001537 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() < 0.0f)
1538 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1539 else if (!foldFloatTypeUnary(operandArray[i], &sqrtf, infoSink, &resultArray[i]))
Arun Patole28eb65e2015-04-06 17:29:48 +05301540 return nullptr;
1541 break;
1542
1543 case EOpInverseSqrt:
1544 // There is no stdlib built-in function equavalent for GLES built-in inversesqrt(),
1545 // so getting the square root first using builtin function sqrt() and then taking its inverse.
1546 // 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 +03001547 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() <= 0.0f)
1548 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1549 else if (!foldFloatTypeUnary(operandArray[i], &sqrtf, infoSink, &resultArray[i]))
Arun Patole28eb65e2015-04-06 17:29:48 +05301550 return nullptr;
1551 else
Olli Etuaho95310b02015-06-02 17:43:38 +03001552 resultArray[i].setFConst(1.0f / resultArray[i].getFConst());
Arun Patole28eb65e2015-04-06 17:29:48 +05301553 break;
1554
Arun Patole9d0b1f92015-05-20 14:27:17 +05301555 case EOpVectorLogicalNot:
1556 if (getType().getBasicType() == EbtBool)
1557 {
Olli Etuaho95310b02015-06-02 17:43:38 +03001558 resultArray[i].setBConst(!operandArray[i].getBConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05301559 break;
1560 }
1561 infoSink.info.message(
1562 EPrefixInternalError, getLine(),
1563 "Unary operation not folded into constant");
1564 return nullptr;
1565
Arun Patole1155ddd2015-06-05 18:04:36 +05301566 case EOpNormalize:
1567 if (getType().getBasicType() == EbtFloat)
1568 {
Olli Etuaho95310b02015-06-02 17:43:38 +03001569 float x = operandArray[i].getFConst();
1570 float length = VectorLength(operandArray, objectSize);
Arun Patole1155ddd2015-06-05 18:04:36 +05301571 if (length)
Olli Etuaho95310b02015-06-02 17:43:38 +03001572 resultArray[i].setFConst(x / length);
Arun Patole1155ddd2015-06-05 18:04:36 +05301573 else
Olli Etuaho95310b02015-06-02 17:43:38 +03001574 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink,
1575 &resultArray[i]);
Arun Patole1155ddd2015-06-05 18:04:36 +05301576 break;
1577 }
1578 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1579 return nullptr;
1580
Jamie Madillb1a85f42014-08-19 15:23:24 -04001581 default:
Arun Patolefddc2112015-04-22 13:28:10 +05301582 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001583 }
1584 }
Olli Etuaho95310b02015-06-02 17:43:38 +03001585 return resultArray;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001586 }
1587}
1588
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001589bool TIntermConstantUnion::foldFloatTypeUnary(const TConstantUnion &parameter, FloatTypeUnaryFunc builtinFunc,
1590 TInfoSink &infoSink, TConstantUnion *result) const
Arun Patole9dea48f2015-04-02 11:45:09 +05301591{
1592 ASSERT(builtinFunc);
1593
1594 if (getType().getBasicType() == EbtFloat)
1595 {
1596 result->setFConst(builtinFunc(parameter.getFConst()));
1597 return true;
1598 }
1599
1600 infoSink.info.message(
1601 EPrefixInternalError, getLine(),
1602 "Unary operation not folded into constant");
1603 return false;
1604}
1605
Jamie Madillb1a85f42014-08-19 15:23:24 -04001606// static
Olli Etuahob43846e2015-06-02 18:18:57 +03001607TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *aggregate, TInfoSink &infoSink)
Arun Patole274f0702015-05-05 13:33:30 +05301608{
Olli Etuahob43846e2015-06-02 18:18:57 +03001609 TOperator op = aggregate->getOp();
Arun Patole274f0702015-05-05 13:33:30 +05301610 TIntermSequence *sequence = aggregate->getSequence();
1611 unsigned int paramsCount = sequence->size();
1612 std::vector<TConstantUnion *> unionArrays(paramsCount);
1613 std::vector<size_t> objectSizes(paramsCount);
Olli Etuahob43846e2015-06-02 18:18:57 +03001614 size_t maxObjectSize = 0;
Arun Patole274f0702015-05-05 13:33:30 +05301615 TBasicType basicType = EbtVoid;
1616 TSourceLoc loc;
1617 for (unsigned int i = 0; i < paramsCount; i++)
1618 {
1619 TIntermConstantUnion *paramConstant = (*sequence)[i]->getAsConstantUnion();
Olli Etuahob43846e2015-06-02 18:18:57 +03001620 ASSERT(paramConstant != nullptr); // Should be checked already.
Arun Patole274f0702015-05-05 13:33:30 +05301621
1622 if (i == 0)
1623 {
1624 basicType = paramConstant->getType().getBasicType();
1625 loc = paramConstant->getLine();
1626 }
1627 unionArrays[i] = paramConstant->getUnionArrayPointer();
1628 objectSizes[i] = paramConstant->getType().getObjectSize();
Olli Etuahob43846e2015-06-02 18:18:57 +03001629 if (objectSizes[i] > maxObjectSize)
1630 maxObjectSize = objectSizes[i];
Arun Patole274f0702015-05-05 13:33:30 +05301631 }
1632
Arun Patole274f0702015-05-05 13:33:30 +05301633 for (unsigned int i = 0; i < paramsCount; i++)
1634 if (objectSizes[i] != maxObjectSize)
1635 unionArrays[i] = Vectorize(*unionArrays[i], maxObjectSize);
1636
Olli Etuahob43846e2015-06-02 18:18:57 +03001637 TConstantUnion *resultArray = nullptr;
Arun Patole274f0702015-05-05 13:33:30 +05301638 if (paramsCount == 2)
1639 {
1640 //
1641 // Binary built-in
1642 //
1643 switch (op)
1644 {
Arun Patolebf790422015-05-18 17:53:04 +05301645 case EOpAtan:
1646 {
1647 if (basicType == EbtFloat)
1648 {
Olli Etuahob43846e2015-06-02 18:18:57 +03001649 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05301650 for (size_t i = 0; i < maxObjectSize; i++)
1651 {
1652 float y = unionArrays[0][i].getFConst();
1653 float x = unionArrays[1][i].getFConst();
1654 // Results are undefined if x and y are both 0.
1655 if (x == 0.0f && y == 0.0f)
Olli Etuahob43846e2015-06-02 18:18:57 +03001656 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patolebf790422015-05-18 17:53:04 +05301657 else
Olli Etuahob43846e2015-06-02 18:18:57 +03001658 resultArray[i].setFConst(atan2f(y, x));
Arun Patolebf790422015-05-18 17:53:04 +05301659 }
1660 }
1661 else
1662 UNREACHABLE();
1663 }
1664 break;
1665
1666 case EOpPow:
1667 {
1668 if (basicType == EbtFloat)
1669 {
Olli Etuahob43846e2015-06-02 18:18:57 +03001670 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05301671 for (size_t i = 0; i < maxObjectSize; i++)
1672 {
1673 float x = unionArrays[0][i].getFConst();
1674 float y = unionArrays[1][i].getFConst();
1675 // Results are undefined if x < 0.
1676 // Results are undefined if x = 0 and y <= 0.
1677 if (x < 0.0f)
Olli Etuahob43846e2015-06-02 18:18:57 +03001678 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patolebf790422015-05-18 17:53:04 +05301679 else if (x == 0.0f && y <= 0.0f)
Olli Etuahob43846e2015-06-02 18:18:57 +03001680 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patolebf790422015-05-18 17:53:04 +05301681 else
Olli Etuahob43846e2015-06-02 18:18:57 +03001682 resultArray[i].setFConst(powf(x, y));
Arun Patolebf790422015-05-18 17:53:04 +05301683 }
1684 }
1685 else
1686 UNREACHABLE();
1687 }
1688 break;
1689
1690 case EOpMod:
1691 {
1692 if (basicType == EbtFloat)
1693 {
Olli Etuahob43846e2015-06-02 18:18:57 +03001694 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05301695 for (size_t i = 0; i < maxObjectSize; i++)
1696 {
1697 float x = unionArrays[0][i].getFConst();
1698 float y = unionArrays[1][i].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03001699 resultArray[i].setFConst(x - y * floorf(x / y));
Arun Patolebf790422015-05-18 17:53:04 +05301700 }
1701 }
1702 else
1703 UNREACHABLE();
1704 }
1705 break;
1706
Arun Patole274f0702015-05-05 13:33:30 +05301707 case EOpMin:
1708 {
Olli Etuahob43846e2015-06-02 18:18:57 +03001709 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole274f0702015-05-05 13:33:30 +05301710 for (size_t i = 0; i < maxObjectSize; i++)
1711 {
1712 switch (basicType)
1713 {
1714 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03001715 resultArray[i].setFConst(std::min(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
Arun Patole274f0702015-05-05 13:33:30 +05301716 break;
1717 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03001718 resultArray[i].setIConst(std::min(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
Arun Patole274f0702015-05-05 13:33:30 +05301719 break;
1720 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03001721 resultArray[i].setUConst(std::min(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
Arun Patole274f0702015-05-05 13:33:30 +05301722 break;
1723 default:
1724 UNREACHABLE();
1725 break;
1726 }
1727 }
1728 }
1729 break;
1730
1731 case EOpMax:
1732 {
Olli Etuahob43846e2015-06-02 18:18:57 +03001733 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole274f0702015-05-05 13:33:30 +05301734 for (size_t i = 0; i < maxObjectSize; i++)
1735 {
1736 switch (basicType)
1737 {
1738 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03001739 resultArray[i].setFConst(std::max(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
Arun Patole274f0702015-05-05 13:33:30 +05301740 break;
1741 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03001742 resultArray[i].setIConst(std::max(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
Arun Patole274f0702015-05-05 13:33:30 +05301743 break;
1744 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03001745 resultArray[i].setUConst(std::max(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
Arun Patole274f0702015-05-05 13:33:30 +05301746 break;
1747 default:
1748 UNREACHABLE();
1749 break;
1750 }
1751 }
1752 }
1753 break;
1754
Arun Patolebf790422015-05-18 17:53:04 +05301755 case EOpStep:
1756 {
1757 if (basicType == EbtFloat)
1758 {
Olli Etuahob43846e2015-06-02 18:18:57 +03001759 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05301760 for (size_t i = 0; i < maxObjectSize; i++)
Olli Etuahob43846e2015-06-02 18:18:57 +03001761 resultArray[i].setFConst(unionArrays[1][i].getFConst() < unionArrays[0][i].getFConst() ? 0.0f : 1.0f);
Arun Patolebf790422015-05-18 17:53:04 +05301762 }
1763 else
1764 UNREACHABLE();
1765 }
1766 break;
1767
Arun Patole9d0b1f92015-05-20 14:27:17 +05301768 case EOpLessThan:
1769 {
Olli Etuahob43846e2015-06-02 18:18:57 +03001770 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05301771 for (size_t i = 0; i < maxObjectSize; i++)
1772 {
1773 switch (basicType)
1774 {
1775 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03001776 resultArray[i].setBConst(unionArrays[0][i].getFConst() < unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05301777 break;
1778 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03001779 resultArray[i].setBConst(unionArrays[0][i].getIConst() < unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05301780 break;
1781 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03001782 resultArray[i].setBConst(unionArrays[0][i].getUConst() < unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05301783 break;
1784 default:
1785 UNREACHABLE();
1786 break;
1787 }
1788 }
1789 }
1790 break;
1791
1792 case EOpLessThanEqual:
1793 {
Olli Etuahob43846e2015-06-02 18:18:57 +03001794 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05301795 for (size_t i = 0; i < maxObjectSize; i++)
1796 {
1797 switch (basicType)
1798 {
1799 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03001800 resultArray[i].setBConst(unionArrays[0][i].getFConst() <= unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05301801 break;
1802 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03001803 resultArray[i].setBConst(unionArrays[0][i].getIConst() <= unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05301804 break;
1805 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03001806 resultArray[i].setBConst(unionArrays[0][i].getUConst() <= unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05301807 break;
1808 default:
1809 UNREACHABLE();
1810 break;
1811 }
1812 }
1813 }
1814 break;
1815
1816 case EOpGreaterThan:
1817 {
Olli Etuahob43846e2015-06-02 18:18:57 +03001818 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05301819 for (size_t i = 0; i < maxObjectSize; i++)
1820 {
1821 switch (basicType)
1822 {
1823 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03001824 resultArray[i].setBConst(unionArrays[0][i].getFConst() > unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05301825 break;
1826 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03001827 resultArray[i].setBConst(unionArrays[0][i].getIConst() > unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05301828 break;
1829 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03001830 resultArray[i].setBConst(unionArrays[0][i].getUConst() > unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05301831 break;
1832 default:
1833 UNREACHABLE();
1834 break;
Olli Etuahob43846e2015-06-02 18:18:57 +03001835 }
1836 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05301837 }
1838 break;
1839
1840 case EOpGreaterThanEqual:
1841 {
Olli Etuahob43846e2015-06-02 18:18:57 +03001842 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05301843 for (size_t i = 0; i < maxObjectSize; i++)
1844 {
1845 switch (basicType)
1846 {
1847 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03001848 resultArray[i].setBConst(unionArrays[0][i].getFConst() >= unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05301849 break;
1850 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03001851 resultArray[i].setBConst(unionArrays[0][i].getIConst() >= unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05301852 break;
1853 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03001854 resultArray[i].setBConst(unionArrays[0][i].getUConst() >= unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05301855 break;
1856 default:
1857 UNREACHABLE();
1858 break;
1859 }
1860 }
1861 }
1862 break;
1863
1864 case EOpVectorEqual:
1865 {
Olli Etuahob43846e2015-06-02 18:18:57 +03001866 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05301867 for (size_t i = 0; i < maxObjectSize; i++)
1868 {
1869 switch (basicType)
1870 {
1871 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03001872 resultArray[i].setBConst(unionArrays[0][i].getFConst() == unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05301873 break;
1874 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03001875 resultArray[i].setBConst(unionArrays[0][i].getIConst() == unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05301876 break;
1877 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03001878 resultArray[i].setBConst(unionArrays[0][i].getUConst() == unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05301879 break;
1880 case EbtBool:
Olli Etuahob43846e2015-06-02 18:18:57 +03001881 resultArray[i].setBConst(unionArrays[0][i].getBConst() == unionArrays[1][i].getBConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05301882 break;
1883 default:
1884 UNREACHABLE();
1885 break;
1886 }
1887 }
1888 }
1889 break;
1890
1891 case EOpVectorNotEqual:
1892 {
Olli Etuahob43846e2015-06-02 18:18:57 +03001893 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05301894 for (size_t i = 0; i < maxObjectSize; i++)
1895 {
1896 switch (basicType)
1897 {
1898 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03001899 resultArray[i].setBConst(unionArrays[0][i].getFConst() != unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05301900 break;
1901 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03001902 resultArray[i].setBConst(unionArrays[0][i].getIConst() != unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05301903 break;
1904 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03001905 resultArray[i].setBConst(unionArrays[0][i].getUConst() != unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05301906 break;
1907 case EbtBool:
Olli Etuahob43846e2015-06-02 18:18:57 +03001908 resultArray[i].setBConst(unionArrays[0][i].getBConst() != unionArrays[1][i].getBConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05301909 break;
1910 default:
1911 UNREACHABLE();
1912 break;
1913 }
1914 }
1915 }
1916 break;
1917
Arun Patole1155ddd2015-06-05 18:04:36 +05301918 case EOpDistance:
1919 if (basicType == EbtFloat)
1920 {
1921 TConstantUnion *distanceArray = new TConstantUnion[maxObjectSize];
Olli Etuahob43846e2015-06-02 18:18:57 +03001922 resultArray = new TConstantUnion();
Arun Patole1155ddd2015-06-05 18:04:36 +05301923 for (size_t i = 0; i < maxObjectSize; i++)
1924 {
1925 float x = unionArrays[0][i].getFConst();
1926 float y = unionArrays[1][i].getFConst();
1927 distanceArray[i].setFConst(x - y);
1928 }
Olli Etuahob43846e2015-06-02 18:18:57 +03001929 resultArray->setFConst(VectorLength(distanceArray, maxObjectSize));
Arun Patole1155ddd2015-06-05 18:04:36 +05301930 }
1931 else
1932 UNREACHABLE();
1933 break;
1934
1935 case EOpDot:
Olli Etuahob43846e2015-06-02 18:18:57 +03001936
Arun Patole1155ddd2015-06-05 18:04:36 +05301937 if (basicType == EbtFloat)
1938 {
Olli Etuahob43846e2015-06-02 18:18:57 +03001939 resultArray = new TConstantUnion();
1940 resultArray->setFConst(VectorDotProduct(unionArrays[0], unionArrays[1], maxObjectSize));
Arun Patole1155ddd2015-06-05 18:04:36 +05301941 }
1942 else
1943 UNREACHABLE();
1944 break;
1945
1946 case EOpCross:
1947 if (basicType == EbtFloat && maxObjectSize == 3)
1948 {
Olli Etuahob43846e2015-06-02 18:18:57 +03001949 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05301950 float x0 = unionArrays[0][0].getFConst();
1951 float x1 = unionArrays[0][1].getFConst();
1952 float x2 = unionArrays[0][2].getFConst();
1953 float y0 = unionArrays[1][0].getFConst();
1954 float y1 = unionArrays[1][1].getFConst();
1955 float y2 = unionArrays[1][2].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03001956 resultArray[0].setFConst(x1 * y2 - y1 * x2);
1957 resultArray[1].setFConst(x2 * y0 - y2 * x0);
1958 resultArray[2].setFConst(x0 * y1 - y0 * x1);
Arun Patole1155ddd2015-06-05 18:04:36 +05301959 }
1960 else
1961 UNREACHABLE();
1962 break;
1963
1964 case EOpReflect:
1965 if (basicType == EbtFloat)
1966 {
1967 // genType reflect (genType I, genType N) :
1968 // For the incident vector I and surface orientation N, returns the reflection direction:
1969 // I - 2 * dot(N, I) * N.
Olli Etuahob43846e2015-06-02 18:18:57 +03001970 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05301971 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
1972 for (size_t i = 0; i < maxObjectSize; i++)
1973 {
1974 float result = unionArrays[0][i].getFConst() -
1975 2.0f * dotProduct * unionArrays[1][i].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03001976 resultArray[i].setFConst(result);
Arun Patole1155ddd2015-06-05 18:04:36 +05301977 }
1978 }
1979 else
1980 UNREACHABLE();
1981 break;
1982
Arun Patole274f0702015-05-05 13:33:30 +05301983 default:
1984 UNREACHABLE();
1985 // TODO: Add constant folding support for other built-in operations that take 2 parameters and not handled above.
1986 return nullptr;
1987 }
1988 }
1989 else if (paramsCount == 3)
1990 {
1991 //
1992 // Ternary built-in
1993 //
1994 switch (op)
1995 {
1996 case EOpClamp:
1997 {
Olli Etuahob43846e2015-06-02 18:18:57 +03001998 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole274f0702015-05-05 13:33:30 +05301999 for (size_t i = 0; i < maxObjectSize; i++)
2000 {
2001 switch (basicType)
2002 {
2003 case EbtFloat:
2004 {
2005 float x = unionArrays[0][i].getFConst();
2006 float min = unionArrays[1][i].getFConst();
2007 float max = unionArrays[2][i].getFConst();
2008 // Results are undefined if min > max.
2009 if (min > max)
Olli Etuahob43846e2015-06-02 18:18:57 +03002010 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302011 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002012 resultArray[i].setFConst(gl::clamp(x, min, max));
Arun Patole274f0702015-05-05 13:33:30 +05302013 }
2014 break;
2015 case EbtInt:
2016 {
2017 int x = unionArrays[0][i].getIConst();
2018 int min = unionArrays[1][i].getIConst();
2019 int max = unionArrays[2][i].getIConst();
2020 // Results are undefined if min > max.
2021 if (min > max)
Olli Etuahob43846e2015-06-02 18:18:57 +03002022 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302023 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002024 resultArray[i].setIConst(gl::clamp(x, min, max));
Arun Patole274f0702015-05-05 13:33:30 +05302025 }
2026 break;
2027 case EbtUInt:
2028 {
2029 unsigned int x = unionArrays[0][i].getUConst();
2030 unsigned int min = unionArrays[1][i].getUConst();
2031 unsigned int max = unionArrays[2][i].getUConst();
2032 // Results are undefined if min > max.
2033 if (min > max)
Olli Etuahob43846e2015-06-02 18:18:57 +03002034 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302035 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002036 resultArray[i].setUConst(gl::clamp(x, min, max));
Arun Patole274f0702015-05-05 13:33:30 +05302037 }
2038 break;
2039 default:
2040 UNREACHABLE();
2041 break;
2042 }
2043 }
2044 }
2045 break;
2046
Arun Patolebf790422015-05-18 17:53:04 +05302047 case EOpMix:
2048 {
2049 if (basicType == EbtFloat)
2050 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002051 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05302052 for (size_t i = 0; i < maxObjectSize; i++)
2053 {
2054 float x = unionArrays[0][i].getFConst();
2055 float y = unionArrays[1][i].getFConst();
2056 TBasicType type = (*sequence)[2]->getAsTyped()->getType().getBasicType();
2057 if (type == EbtFloat)
2058 {
2059 // Returns the linear blend of x and y, i.e., x * (1 - a) + y * a.
2060 float a = unionArrays[2][i].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002061 resultArray[i].setFConst(x * (1.0f - a) + y * a);
Arun Patolebf790422015-05-18 17:53:04 +05302062 }
2063 else // 3rd parameter is EbtBool
2064 {
2065 ASSERT(type == EbtBool);
2066 // Selects which vector each returned component comes from.
2067 // For a component of a that is false, the corresponding component of x is returned.
2068 // For a component of a that is true, the corresponding component of y is returned.
2069 bool a = unionArrays[2][i].getBConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002070 resultArray[i].setFConst(a ? y : x);
Arun Patolebf790422015-05-18 17:53:04 +05302071 }
2072 }
2073 }
2074 else
2075 UNREACHABLE();
2076 }
2077 break;
2078
2079 case EOpSmoothStep:
2080 {
2081 if (basicType == EbtFloat)
2082 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002083 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05302084 for (size_t i = 0; i < maxObjectSize; i++)
2085 {
2086 float edge0 = unionArrays[0][i].getFConst();
2087 float edge1 = unionArrays[1][i].getFConst();
2088 float x = unionArrays[2][i].getFConst();
2089 // Results are undefined if edge0 >= edge1.
2090 if (edge0 >= edge1)
2091 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002092 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patolebf790422015-05-18 17:53:04 +05302093 }
2094 else
2095 {
2096 // Returns 0.0 if x <= edge0 and 1.0 if x >= edge1 and performs smooth
2097 // Hermite interpolation between 0 and 1 when edge0 < x < edge1.
2098 float t = gl::clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f);
Olli Etuahob43846e2015-06-02 18:18:57 +03002099 resultArray[i].setFConst(t * t * (3.0f - 2.0f * t));
Arun Patolebf790422015-05-18 17:53:04 +05302100 }
2101 }
2102 }
2103 else
2104 UNREACHABLE();
2105 }
2106 break;
2107
Arun Patole1155ddd2015-06-05 18:04:36 +05302108 case EOpFaceForward:
2109 if (basicType == EbtFloat)
2110 {
2111 // genType faceforward(genType N, genType I, genType Nref) :
2112 // If dot(Nref, I) < 0 return N, otherwise return -N.
Olli Etuahob43846e2015-06-02 18:18:57 +03002113 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302114 float dotProduct = VectorDotProduct(unionArrays[2], unionArrays[1], maxObjectSize);
2115 for (size_t i = 0; i < maxObjectSize; i++)
2116 {
2117 if (dotProduct < 0)
Olli Etuahob43846e2015-06-02 18:18:57 +03002118 resultArray[i].setFConst(unionArrays[0][i].getFConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05302119 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002120 resultArray[i].setFConst(-unionArrays[0][i].getFConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05302121 }
2122 }
2123 else
2124 UNREACHABLE();
2125 break;
2126
2127 case EOpRefract:
2128 if (basicType == EbtFloat)
2129 {
2130 // genType refract(genType I, genType N, float eta) :
2131 // For the incident vector I and surface normal N, and the ratio of indices of refraction eta,
2132 // return the refraction vector. The result is computed by
2133 // k = 1.0 - eta * eta * (1.0 - dot(N, I) * dot(N, I))
2134 // if (k < 0.0)
2135 // return genType(0.0)
2136 // else
2137 // return eta * I - (eta * dot(N, I) + sqrt(k)) * N
Olli Etuahob43846e2015-06-02 18:18:57 +03002138 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302139 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
2140 for (size_t i = 0; i < maxObjectSize; i++)
2141 {
2142 float eta = unionArrays[2][i].getFConst();
2143 float k = 1.0f - eta * eta * (1.0f - dotProduct * dotProduct);
2144 if (k < 0.0f)
Olli Etuahob43846e2015-06-02 18:18:57 +03002145 resultArray[i].setFConst(0.0f);
Arun Patole1155ddd2015-06-05 18:04:36 +05302146 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002147 resultArray[i].setFConst(eta * unionArrays[0][i].getFConst() -
Arun Patole1155ddd2015-06-05 18:04:36 +05302148 (eta * dotProduct + sqrtf(k)) * unionArrays[1][i].getFConst());
2149 }
2150 }
2151 else
2152 UNREACHABLE();
2153 break;
2154
Arun Patole274f0702015-05-05 13:33:30 +05302155 default:
2156 UNREACHABLE();
2157 // TODO: Add constant folding support for other built-in operations that take 3 parameters and not handled above.
2158 return nullptr;
2159 }
2160 }
Olli Etuahob43846e2015-06-02 18:18:57 +03002161 return resultArray;
Arun Patole274f0702015-05-05 13:33:30 +05302162}
2163
2164// static
Jamie Madillb1a85f42014-08-19 15:23:24 -04002165TString TIntermTraverser::hash(const TString &name, ShHashFunction64 hashFunction)
2166{
2167 if (hashFunction == NULL || name.empty())
2168 return name;
2169 khronos_uint64_t number = (*hashFunction)(name.c_str(), name.length());
2170 TStringStream stream;
2171 stream << HASHED_NAME_PREFIX << std::hex << number;
2172 TString hashedName = stream.str();
2173 return hashedName;
2174}
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002175
2176void TIntermTraverser::updateTree()
2177{
Olli Etuahoa6f22092015-05-08 18:31:10 +03002178 for (size_t ii = 0; ii < mInsertions.size(); ++ii)
2179 {
2180 const NodeInsertMultipleEntry &insertion = mInsertions[ii];
2181 ASSERT(insertion.parent);
2182 bool inserted = insertion.parent->insertChildNodes(insertion.position, insertion.insertions);
2183 ASSERT(inserted);
2184 UNUSED_ASSERTION_VARIABLE(inserted);
2185 }
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002186 for (size_t ii = 0; ii < mReplacements.size(); ++ii)
2187 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03002188 const NodeUpdateEntry &replacement = mReplacements[ii];
2189 ASSERT(replacement.parent);
2190 bool replaced = replacement.parent->replaceChildNode(
2191 replacement.original, replacement.replacement);
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002192 ASSERT(replaced);
Olli Etuahod57e0db2015-04-24 15:05:08 +03002193 UNUSED_ASSERTION_VARIABLE(replaced);
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002194
Olli Etuahocd94ef92015-04-16 19:18:10 +03002195 if (!replacement.originalBecomesChildOfReplacement)
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002196 {
2197 // In AST traversing, a parent is visited before its children.
Olli Etuahocd94ef92015-04-16 19:18:10 +03002198 // After we replace a node, if its immediate child is to
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002199 // be replaced, we need to make sure we don't update the replaced
2200 // node; instead, we update the replacement node.
2201 for (size_t jj = ii + 1; jj < mReplacements.size(); ++jj)
2202 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03002203 NodeUpdateEntry &replacement2 = mReplacements[jj];
2204 if (replacement2.parent == replacement.original)
2205 replacement2.parent = replacement.replacement;
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002206 }
2207 }
2208 }
Olli Etuahofc0e2bc2015-04-16 13:39:56 +03002209 for (size_t ii = 0; ii < mMultiReplacements.size(); ++ii)
2210 {
2211 const NodeReplaceWithMultipleEntry &replacement = mMultiReplacements[ii];
2212 ASSERT(replacement.parent);
2213 bool replaced = replacement.parent->replaceChildNodeWithMultiple(
2214 replacement.original, replacement.replacements);
2215 ASSERT(replaced);
Olli Etuahod57e0db2015-04-24 15:05:08 +03002216 UNUSED_ASSERTION_VARIABLE(replaced);
Olli Etuahofc0e2bc2015-04-16 13:39:56 +03002217 }
Olli Etuahod4f303e2015-05-20 17:09:06 +03002218
2219 mInsertions.clear();
2220 mReplacements.clear();
2221 mMultiReplacements.clear();
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002222}