blob: cb32cd75304a615cc36be576d5a0d22c9f0c84ba [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{
298 if (getBasicType() == EbtBool)
299 {
300 mType.setPrecision(EbpUndefined);
301 return;
302 }
303
304 TPrecision precision = EbpUndefined;
305 TIntermSequence::iterator childIter = mSequence.begin();
306 while (childIter != mSequence.end())
307 {
308 TIntermTyped *typed = (*childIter)->getAsTyped();
309 if (typed)
310 precision = GetHigherPrecision(typed->getPrecision(), precision);
311 ++childIter;
312 }
313 mType.setPrecision(precision);
314}
315
316void TIntermAggregate::setBuiltInFunctionPrecision()
317{
318 // All built-ins returning bool should be handled as ops, not functions.
319 ASSERT(getBasicType() != EbtBool);
320
321 TPrecision precision = EbpUndefined;
322 TIntermSequence::iterator childIter = mSequence.begin();
323 while (childIter != mSequence.end())
324 {
325 TIntermTyped *typed = (*childIter)->getAsTyped();
326 // ESSL spec section 8: texture functions get their precision from the sampler.
327 if (typed && IsSampler(typed->getBasicType()))
328 {
329 precision = typed->getPrecision();
330 break;
331 }
332 ++childIter;
333 }
334 // ESSL 3.0 spec section 8: textureSize always gets highp precision.
335 // All other functions that take a sampler are assumed to be texture functions.
336 if (mName.find("textureSize") == 0)
337 mType.setPrecision(EbpHigh);
338 else
339 mType.setPrecision(precision);
340}
341
Jamie Madillb1a85f42014-08-19 15:23:24 -0400342bool TIntermSelection::replaceChildNode(
343 TIntermNode *original, TIntermNode *replacement)
344{
345 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
346 REPLACE_IF_IS(mTrueBlock, TIntermNode, original, replacement);
347 REPLACE_IF_IS(mFalseBlock, TIntermNode, original, replacement);
348 return false;
349}
350
Olli Etuahoa3a36662015-02-17 13:46:51 +0200351bool TIntermSwitch::replaceChildNode(
352 TIntermNode *original, TIntermNode *replacement)
353{
354 REPLACE_IF_IS(mInit, TIntermTyped, original, replacement);
355 REPLACE_IF_IS(mStatementList, TIntermAggregate, original, replacement);
356 return false;
357}
358
359bool TIntermCase::replaceChildNode(
360 TIntermNode *original, TIntermNode *replacement)
361{
362 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
363 return false;
364}
365
Jamie Madillb1a85f42014-08-19 15:23:24 -0400366//
367// Say whether or not an operation node changes the value of a variable.
368//
369bool TIntermOperator::isAssignment() const
370{
371 switch (mOp)
372 {
373 case EOpPostIncrement:
374 case EOpPostDecrement:
375 case EOpPreIncrement:
376 case EOpPreDecrement:
377 case EOpAssign:
378 case EOpAddAssign:
379 case EOpSubAssign:
380 case EOpMulAssign:
381 case EOpVectorTimesMatrixAssign:
382 case EOpVectorTimesScalarAssign:
383 case EOpMatrixTimesScalarAssign:
384 case EOpMatrixTimesMatrixAssign:
385 case EOpDivAssign:
Olli Etuahoff805cc2015-02-13 10:59:34 +0200386 case EOpIModAssign:
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200387 case EOpBitShiftLeftAssign:
388 case EOpBitShiftRightAssign:
389 case EOpBitwiseAndAssign:
390 case EOpBitwiseXorAssign:
391 case EOpBitwiseOrAssign:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400392 return true;
393 default:
394 return false;
395 }
396}
397
Olli Etuaho8f76bcc2015-06-02 13:54:20 +0300398bool TIntermOperator::isMultiplication() const
399{
400 switch (mOp)
401 {
402 case EOpMul:
403 case EOpMatrixTimesMatrix:
404 case EOpMatrixTimesVector:
405 case EOpMatrixTimesScalar:
406 case EOpVectorTimesMatrix:
407 case EOpVectorTimesScalar:
408 return true;
409 default:
410 return false;
411 }
412}
413
Jamie Madillb1a85f42014-08-19 15:23:24 -0400414//
415// returns true if the operator is for one of the constructors
416//
417bool TIntermOperator::isConstructor() const
418{
419 switch (mOp)
420 {
421 case EOpConstructVec2:
422 case EOpConstructVec3:
423 case EOpConstructVec4:
424 case EOpConstructMat2:
425 case EOpConstructMat3:
426 case EOpConstructMat4:
427 case EOpConstructFloat:
428 case EOpConstructIVec2:
429 case EOpConstructIVec3:
430 case EOpConstructIVec4:
431 case EOpConstructInt:
432 case EOpConstructUVec2:
433 case EOpConstructUVec3:
434 case EOpConstructUVec4:
435 case EOpConstructUInt:
436 case EOpConstructBVec2:
437 case EOpConstructBVec3:
438 case EOpConstructBVec4:
439 case EOpConstructBool:
440 case EOpConstructStruct:
441 return true;
442 default:
443 return false;
444 }
445}
446
447//
448// Make sure the type of a unary operator is appropriate for its
449// combination of operation and operand type.
450//
Olli Etuahof6c694b2015-03-26 14:50:53 +0200451void TIntermUnary::promote(const TType *funcReturnType)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400452{
453 switch (mOp)
454 {
Olli Etuahodca3e792015-03-26 13:24:04 +0200455 case EOpFloatBitsToInt:
456 case EOpFloatBitsToUint:
Olli Etuahoe8d2c072015-01-08 16:33:54 +0200457 case EOpIntBitsToFloat:
458 case EOpUintBitsToFloat:
Olli Etuahodca3e792015-03-26 13:24:04 +0200459 case EOpPackSnorm2x16:
460 case EOpPackUnorm2x16:
461 case EOpPackHalf2x16:
Olli Etuaho7700ff62015-01-15 12:16:29 +0200462 case EOpUnpackSnorm2x16:
463 case EOpUnpackUnorm2x16:
Olli Etuahodca3e792015-03-26 13:24:04 +0200464 mType.setPrecision(EbpHigh);
Arun Patole6b19d762015-02-19 09:40:39 +0530465 break;
Olli Etuahodca3e792015-03-26 13:24:04 +0200466 case EOpUnpackHalf2x16:
467 mType.setPrecision(EbpMedium);
468 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400469 default:
Olli Etuahodca3e792015-03-26 13:24:04 +0200470 setType(mOperand->getType());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400471 }
472
Olli Etuahof6c694b2015-03-26 14:50:53 +0200473 if (funcReturnType != nullptr)
474 {
475 if (funcReturnType->getBasicType() == EbtBool)
476 {
477 // Bool types should not have precision.
478 setType(*funcReturnType);
479 }
480 else
481 {
482 // Precision of the node has been set based on the operand.
483 setTypePreservePrecision(*funcReturnType);
484 }
485 }
486
Jamie Madillb1a85f42014-08-19 15:23:24 -0400487 mType.setQualifier(EvqTemporary);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400488}
489
490//
491// Establishes the type of the resultant operation, as well as
492// makes the operator the correct one for the operands.
493//
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200494// For lots of operations it should already be established that the operand
495// combination is valid, but returns false if operator can't work on operands.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400496//
497bool TIntermBinary::promote(TInfoSink &infoSink)
498{
Olli Etuahoe79904c2015-03-18 16:56:42 +0200499 ASSERT(mLeft->isArray() == mRight->isArray());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400500
Jamie Madillb1a85f42014-08-19 15:23:24 -0400501 //
502 // Base assumption: just make the type the same as the left
503 // operand. Then only deviations from this need be coded.
504 //
505 setType(mLeft->getType());
506
507 // The result gets promoted to the highest precision.
508 TPrecision higherPrecision = GetHigherPrecision(
509 mLeft->getPrecision(), mRight->getPrecision());
510 getTypePointer()->setPrecision(higherPrecision);
511
512 // Binary operations results in temporary variables unless both
513 // operands are const.
514 if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst)
515 {
516 getTypePointer()->setQualifier(EvqTemporary);
517 }
518
519 const int nominalSize =
520 std::max(mLeft->getNominalSize(), mRight->getNominalSize());
521
522 //
523 // All scalars or structs. Code after this test assumes this case is removed!
524 //
525 if (nominalSize == 1)
526 {
527 switch (mOp)
528 {
529 //
530 // Promote to conditional
531 //
532 case EOpEqual:
533 case EOpNotEqual:
534 case EOpLessThan:
535 case EOpGreaterThan:
536 case EOpLessThanEqual:
537 case EOpGreaterThanEqual:
538 setType(TType(EbtBool, EbpUndefined));
539 break;
540
541 //
542 // And and Or operate on conditionals
543 //
544 case EOpLogicalAnd:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200545 case EOpLogicalXor:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400546 case EOpLogicalOr:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200547 ASSERT(mLeft->getBasicType() == EbtBool && mRight->getBasicType() == EbtBool);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400548 setType(TType(EbtBool, EbpUndefined));
549 break;
550
551 default:
552 break;
553 }
554 return true;
555 }
556
557 // If we reach here, at least one of the operands is vector or matrix.
558 // The other operand could be a scalar, vector, or matrix.
559 // Can these two operands be combined?
560 //
561 TBasicType basicType = mLeft->getBasicType();
562 switch (mOp)
563 {
564 case EOpMul:
565 if (!mLeft->isMatrix() && mRight->isMatrix())
566 {
567 if (mLeft->isVector())
568 {
569 mOp = EOpVectorTimesMatrix;
570 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700571 static_cast<unsigned char>(mRight->getCols()), 1));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400572 }
573 else
574 {
575 mOp = EOpMatrixTimesScalar;
576 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700577 static_cast<unsigned char>(mRight->getCols()), static_cast<unsigned char>(mRight->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400578 }
579 }
580 else if (mLeft->isMatrix() && !mRight->isMatrix())
581 {
582 if (mRight->isVector())
583 {
584 mOp = EOpMatrixTimesVector;
585 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700586 static_cast<unsigned char>(mLeft->getRows()), 1));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400587 }
588 else
589 {
590 mOp = EOpMatrixTimesScalar;
591 }
592 }
593 else if (mLeft->isMatrix() && mRight->isMatrix())
594 {
595 mOp = EOpMatrixTimesMatrix;
596 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700597 static_cast<unsigned char>(mRight->getCols()), static_cast<unsigned char>(mLeft->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400598 }
599 else if (!mLeft->isMatrix() && !mRight->isMatrix())
600 {
601 if (mLeft->isVector() && mRight->isVector())
602 {
603 // leave as component product
604 }
605 else if (mLeft->isVector() || mRight->isVector())
606 {
607 mOp = EOpVectorTimesScalar;
608 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700609 static_cast<unsigned char>(nominalSize), 1));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400610 }
611 }
612 else
613 {
614 infoSink.info.message(EPrefixInternalError, getLine(),
615 "Missing elses");
616 return false;
617 }
618
619 if (!ValidateMultiplication(mOp, mLeft->getType(), mRight->getType()))
620 {
621 return false;
622 }
623 break;
624
625 case EOpMulAssign:
626 if (!mLeft->isMatrix() && mRight->isMatrix())
627 {
628 if (mLeft->isVector())
629 {
630 mOp = EOpVectorTimesMatrixAssign;
631 }
632 else
633 {
634 return false;
635 }
636 }
637 else if (mLeft->isMatrix() && !mRight->isMatrix())
638 {
639 if (mRight->isVector())
640 {
641 return false;
642 }
643 else
644 {
645 mOp = EOpMatrixTimesScalarAssign;
646 }
647 }
648 else if (mLeft->isMatrix() && mRight->isMatrix())
649 {
650 mOp = EOpMatrixTimesMatrixAssign;
651 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700652 static_cast<unsigned char>(mRight->getCols()), static_cast<unsigned char>(mLeft->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400653 }
654 else if (!mLeft->isMatrix() && !mRight->isMatrix())
655 {
656 if (mLeft->isVector() && mRight->isVector())
657 {
658 // leave as component product
659 }
660 else if (mLeft->isVector() || mRight->isVector())
661 {
662 if (!mLeft->isVector())
663 return false;
664 mOp = EOpVectorTimesScalarAssign;
665 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700666 static_cast<unsigned char>(mLeft->getNominalSize()), 1));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400667 }
668 }
669 else
670 {
671 infoSink.info.message(EPrefixInternalError, getLine(),
672 "Missing elses");
673 return false;
674 }
675
676 if (!ValidateMultiplication(mOp, mLeft->getType(), mRight->getType()))
677 {
678 return false;
679 }
680 break;
681
682 case EOpAssign:
683 case EOpInitialize:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200684 // No more additional checks are needed.
685 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
686 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
687 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400688 case EOpAdd:
689 case EOpSub:
690 case EOpDiv:
Olli Etuahoff805cc2015-02-13 10:59:34 +0200691 case EOpIMod:
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200692 case EOpBitShiftLeft:
693 case EOpBitShiftRight:
694 case EOpBitwiseAnd:
695 case EOpBitwiseXor:
696 case EOpBitwiseOr:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400697 case EOpAddAssign:
698 case EOpSubAssign:
699 case EOpDivAssign:
Olli Etuahoff805cc2015-02-13 10:59:34 +0200700 case EOpIModAssign:
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200701 case EOpBitShiftLeftAssign:
702 case EOpBitShiftRightAssign:
703 case EOpBitwiseAndAssign:
704 case EOpBitwiseXorAssign:
705 case EOpBitwiseOrAssign:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400706 if ((mLeft->isMatrix() && mRight->isVector()) ||
707 (mLeft->isVector() && mRight->isMatrix()))
708 {
709 return false;
710 }
711
712 // Are the sizes compatible?
713 if (mLeft->getNominalSize() != mRight->getNominalSize() ||
714 mLeft->getSecondarySize() != mRight->getSecondarySize())
715 {
Olli Etuaho6c850472014-12-02 16:23:17 +0200716 // If the nominal sizes of operands do not match:
717 // One of them must be a scalar.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400718 if (!mLeft->isScalar() && !mRight->isScalar())
719 return false;
720
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200721 // In the case of compound assignment other than multiply-assign,
722 // the right side needs to be a scalar. Otherwise a vector/matrix
723 // would be assigned to a scalar. A scalar can't be shifted by a
724 // vector either.
Olli Etuaho6c850472014-12-02 16:23:17 +0200725 if (!mRight->isScalar() &&
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200726 (isAssignment() ||
727 mOp == EOpBitShiftLeft ||
728 mOp == EOpBitShiftRight))
Olli Etuaho6c850472014-12-02 16:23:17 +0200729 return false;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400730 }
731
732 {
733 const int secondarySize = std::max(
734 mLeft->getSecondarySize(), mRight->getSecondarySize());
735 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700736 static_cast<unsigned char>(nominalSize), static_cast<unsigned char>(secondarySize)));
Olli Etuahoe79904c2015-03-18 16:56:42 +0200737 if (mLeft->isArray())
738 {
739 ASSERT(mLeft->getArraySize() == mRight->getArraySize());
740 mType.setArraySize(mLeft->getArraySize());
741 }
Jamie Madillb1a85f42014-08-19 15:23:24 -0400742 }
743 break;
744
745 case EOpEqual:
746 case EOpNotEqual:
747 case EOpLessThan:
748 case EOpGreaterThan:
749 case EOpLessThanEqual:
750 case EOpGreaterThanEqual:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200751 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
752 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400753 setType(TType(EbtBool, EbpUndefined));
754 break;
755
756 default:
757 return false;
758 }
759 return true;
760}
761
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300762TIntermTyped *TIntermBinary::fold(TInfoSink &infoSink)
763{
764 TIntermConstantUnion *leftConstant = mLeft->getAsConstantUnion();
765 TIntermConstantUnion *rightConstant = mRight->getAsConstantUnion();
766 if (leftConstant == nullptr || rightConstant == nullptr)
767 {
768 return nullptr;
769 }
770 TConstantUnion *constArray = leftConstant->foldBinary(mOp, rightConstant, infoSink);
Olli Etuahob43846e2015-06-02 18:18:57 +0300771 return CreateFoldedNode(constArray, this);
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300772}
773
Olli Etuaho95310b02015-06-02 17:43:38 +0300774TIntermTyped *TIntermUnary::fold(TInfoSink &infoSink)
775{
776 TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
777 if (operandConstant == nullptr)
778 {
779 return nullptr;
780 }
781 TConstantUnion *constArray = operandConstant->foldUnary(mOp, infoSink);
Olli Etuahob43846e2015-06-02 18:18:57 +0300782 return CreateFoldedNode(constArray, this);
783}
784
785TIntermTyped *TIntermAggregate::fold(TInfoSink &infoSink)
786{
787 // Make sure that all params are constant before actual constant folding.
788 for (auto *param : *getSequence())
Olli Etuaho95310b02015-06-02 17:43:38 +0300789 {
Olli Etuahob43846e2015-06-02 18:18:57 +0300790 if (param->getAsConstantUnion() == nullptr)
791 {
792 return nullptr;
793 }
Olli Etuaho95310b02015-06-02 17:43:38 +0300794 }
Olli Etuahob43846e2015-06-02 18:18:57 +0300795 TConstantUnion *constArray = TIntermConstantUnion::FoldAggregateBuiltIn(this, infoSink);
796 return CreateFoldedNode(constArray, this);
Olli Etuaho95310b02015-06-02 17:43:38 +0300797}
798
Jamie Madillb1a85f42014-08-19 15:23:24 -0400799//
800// The fold functions see if an operation on a constant can be done in place,
801// without generating run-time code.
802//
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300803// Returns the constant value to keep using or nullptr.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400804//
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300805TConstantUnion *TIntermConstantUnion::foldBinary(TOperator op, TIntermConstantUnion *rightNode, TInfoSink &infoSink)
806{
807 TConstantUnion *leftArray = getUnionArrayPointer();
808 TConstantUnion *rightArray = rightNode->getUnionArrayPointer();
809
810 if (!leftArray)
811 return nullptr;
812 if (!rightArray)
813 return nullptr;
814
815 size_t objectSize = getType().getObjectSize();
816
817 // for a case like float f = vec4(2, 3, 4, 5) + 1.2;
818 if (rightNode->getType().getObjectSize() == 1 && objectSize > 1)
819 {
820 rightArray = Vectorize(*rightNode->getUnionArrayPointer(), objectSize);
821 }
822 else if (rightNode->getType().getObjectSize() > 1 && objectSize == 1)
823 {
824 // for a case like float f = 1.2 + vec4(2, 3, 4, 5);
825 leftArray = Vectorize(*getUnionArrayPointer(), rightNode->getType().getObjectSize());
826 objectSize = rightNode->getType().getObjectSize();
827 }
828
829 TConstantUnion *resultArray = nullptr;
830
831 switch(op)
832 {
833 case EOpAdd:
834 resultArray = new TConstantUnion[objectSize];
835 for (size_t i = 0; i < objectSize; i++)
836 resultArray[i] = leftArray[i] + rightArray[i];
837 break;
838 case EOpSub:
839 resultArray = new TConstantUnion[objectSize];
840 for (size_t i = 0; i < objectSize; i++)
841 resultArray[i] = leftArray[i] - rightArray[i];
842 break;
843
844 case EOpMul:
845 case EOpVectorTimesScalar:
846 case EOpMatrixTimesScalar:
847 resultArray = new TConstantUnion[objectSize];
848 for (size_t i = 0; i < objectSize; i++)
849 resultArray[i] = leftArray[i] * rightArray[i];
850 break;
851
852 case EOpMatrixTimesMatrix:
853 {
854 if (getType().getBasicType() != EbtFloat ||
855 rightNode->getBasicType() != EbtFloat)
856 {
857 infoSink.info.message(
858 EPrefixInternalError, getLine(),
859 "Constant Folding cannot be done for matrix multiply");
860 return nullptr;
861 }
862
863 const int leftCols = getCols();
864 const int leftRows = getRows();
865 const int rightCols = rightNode->getType().getCols();
866 const int rightRows = rightNode->getType().getRows();
867 const int resultCols = rightCols;
868 const int resultRows = leftRows;
869
870 resultArray = new TConstantUnion[resultCols * resultRows];
871 for (int row = 0; row < resultRows; row++)
872 {
873 for (int column = 0; column < resultCols; column++)
874 {
875 resultArray[resultRows * column + row].setFConst(0.0f);
876 for (int i = 0; i < leftCols; i++)
877 {
878 resultArray[resultRows * column + row].setFConst(
879 resultArray[resultRows * column + row].getFConst() +
880 leftArray[i * leftRows + row].getFConst() *
881 rightArray[column * rightRows + i].getFConst());
882 }
883 }
884 }
885 }
886 break;
887
888 case EOpDiv:
889 case EOpIMod:
890 {
891 resultArray = new TConstantUnion[objectSize];
892 for (size_t i = 0; i < objectSize; i++)
893 {
894 switch (getType().getBasicType())
895 {
896 case EbtFloat:
897 if (rightArray[i] == 0.0f)
898 {
899 infoSink.info.message(EPrefixWarning, getLine(),
900 "Divide by zero error during constant folding");
901 resultArray[i].setFConst(leftArray[i].getFConst() < 0 ? -FLT_MAX : FLT_MAX);
902 }
903 else
904 {
905 ASSERT(op == EOpDiv);
906 resultArray[i].setFConst(leftArray[i].getFConst() / rightArray[i].getFConst());
907 }
908 break;
909
910 case EbtInt:
911 if (rightArray[i] == 0)
912 {
913 infoSink.info.message(EPrefixWarning, getLine(),
914 "Divide by zero error during constant folding");
915 resultArray[i].setIConst(INT_MAX);
916 }
917 else
918 {
919 if (op == EOpDiv)
920 {
921 resultArray[i].setIConst(leftArray[i].getIConst() / rightArray[i].getIConst());
922 }
923 else
924 {
925 ASSERT(op == EOpIMod);
926 resultArray[i].setIConst(leftArray[i].getIConst() % rightArray[i].getIConst());
927 }
928 }
929 break;
930
931 case EbtUInt:
932 if (rightArray[i] == 0)
933 {
934 infoSink.info.message(EPrefixWarning, getLine(),
935 "Divide by zero error during constant folding");
936 resultArray[i].setUConst(UINT_MAX);
937 }
938 else
939 {
940 if (op == EOpDiv)
941 {
942 resultArray[i].setUConst(leftArray[i].getUConst() / rightArray[i].getUConst());
943 }
944 else
945 {
946 ASSERT(op == EOpIMod);
947 resultArray[i].setUConst(leftArray[i].getUConst() % rightArray[i].getUConst());
948 }
949 }
950 break;
951
952 default:
953 infoSink.info.message(EPrefixInternalError, getLine(),
954 "Constant folding cannot be done for \"/\"");
955 return nullptr;
956 }
957 }
958 }
959 break;
960
961 case EOpMatrixTimesVector:
962 {
963 if (rightNode->getBasicType() != EbtFloat)
964 {
965 infoSink.info.message(EPrefixInternalError, getLine(),
966 "Constant Folding cannot be done for matrix times vector");
967 return nullptr;
968 }
969
970 const int matrixCols = getCols();
971 const int matrixRows = getRows();
972
973 resultArray = new TConstantUnion[matrixRows];
974
975 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
976 {
977 resultArray[matrixRow].setFConst(0.0f);
978 for (int col = 0; col < matrixCols; col++)
979 {
980 resultArray[matrixRow].setFConst(resultArray[matrixRow].getFConst() +
981 leftArray[col * matrixRows + matrixRow].getFConst() *
982 rightArray[col].getFConst());
983 }
984 }
985 }
986 break;
987
988 case EOpVectorTimesMatrix:
989 {
990 if (getType().getBasicType() != EbtFloat)
991 {
992 infoSink.info.message(EPrefixInternalError, getLine(),
993 "Constant Folding cannot be done for vector times matrix");
994 return nullptr;
995 }
996
997 const int matrixCols = rightNode->getType().getCols();
998 const int matrixRows = rightNode->getType().getRows();
999
1000 resultArray = new TConstantUnion[matrixCols];
1001
1002 for (int matrixCol = 0; matrixCol < matrixCols; matrixCol++)
1003 {
1004 resultArray[matrixCol].setFConst(0.0f);
1005 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1006 {
1007 resultArray[matrixCol].setFConst(resultArray[matrixCol].getFConst() +
1008 leftArray[matrixRow].getFConst() *
1009 rightArray[matrixCol * matrixRows + matrixRow].getFConst());
1010 }
1011 }
1012 }
1013 break;
1014
1015 case EOpLogicalAnd:
1016 {
1017 resultArray = new TConstantUnion[objectSize];
1018 for (size_t i = 0; i < objectSize; i++)
1019 {
1020 resultArray[i] = leftArray[i] && rightArray[i];
1021 }
1022 }
1023 break;
1024
1025 case EOpLogicalOr:
1026 {
1027 resultArray = new TConstantUnion[objectSize];
1028 for (size_t i = 0; i < objectSize; i++)
1029 {
1030 resultArray[i] = leftArray[i] || rightArray[i];
1031 }
1032 }
1033 break;
1034
1035 case EOpLogicalXor:
1036 {
1037 resultArray = new TConstantUnion[objectSize];
1038 for (size_t i = 0; i < objectSize; i++)
1039 {
1040 switch (getType().getBasicType())
1041 {
1042 case EbtBool:
1043 resultArray[i].setBConst(leftArray[i] != rightArray[i]);
1044 break;
1045 default:
1046 UNREACHABLE();
1047 break;
1048 }
1049 }
1050 }
1051 break;
1052
1053 case EOpBitwiseAnd:
1054 resultArray = new TConstantUnion[objectSize];
1055 for (size_t i = 0; i < objectSize; i++)
1056 resultArray[i] = leftArray[i] & rightArray[i];
1057 break;
1058 case EOpBitwiseXor:
1059 resultArray = new TConstantUnion[objectSize];
1060 for (size_t i = 0; i < objectSize; i++)
1061 resultArray[i] = leftArray[i] ^ rightArray[i];
1062 break;
1063 case EOpBitwiseOr:
1064 resultArray = new TConstantUnion[objectSize];
1065 for (size_t i = 0; i < objectSize; i++)
1066 resultArray[i] = leftArray[i] | rightArray[i];
1067 break;
1068 case EOpBitShiftLeft:
1069 resultArray = new TConstantUnion[objectSize];
1070 for (size_t i = 0; i < objectSize; i++)
1071 resultArray[i] = leftArray[i] << rightArray[i];
1072 break;
1073 case EOpBitShiftRight:
1074 resultArray = new TConstantUnion[objectSize];
1075 for (size_t i = 0; i < objectSize; i++)
1076 resultArray[i] = leftArray[i] >> rightArray[i];
1077 break;
1078
1079 case EOpLessThan:
1080 ASSERT(objectSize == 1);
1081 resultArray = new TConstantUnion[1];
1082 resultArray->setBConst(*leftArray < *rightArray);
1083 break;
1084
1085 case EOpGreaterThan:
1086 ASSERT(objectSize == 1);
1087 resultArray = new TConstantUnion[1];
1088 resultArray->setBConst(*leftArray > *rightArray);
1089 break;
1090
1091 case EOpLessThanEqual:
1092 ASSERT(objectSize == 1);
1093 resultArray = new TConstantUnion[1];
1094 resultArray->setBConst(!(*leftArray > *rightArray));
1095 break;
1096
1097 case EOpGreaterThanEqual:
1098 ASSERT(objectSize == 1);
1099 resultArray = new TConstantUnion[1];
1100 resultArray->setBConst(!(*leftArray < *rightArray));
1101 break;
1102
1103 case EOpEqual:
1104 case EOpNotEqual:
1105 {
1106 resultArray = new TConstantUnion[1];
1107 bool equal = true;
1108 if (getType().getBasicType() == EbtStruct)
1109 {
1110 equal = CompareStructure(getType(), rightArray, leftArray);
1111 }
1112 else
1113 {
1114 for (size_t i = 0; i < objectSize; i++)
1115 {
1116 if (leftArray[i] != rightArray[i])
1117 {
1118 equal = false;
1119 break; // break out of for loop
1120 }
1121 }
1122 }
1123 if (op == EOpEqual)
1124 {
1125 resultArray->setBConst(equal);
1126 }
1127 else
1128 {
1129 resultArray->setBConst(!equal);
1130 }
1131 }
1132 break;
1133
1134 default:
1135 infoSink.info.message(
1136 EPrefixInternalError, getLine(),
1137 "Invalid operator for constant folding");
1138 return nullptr;
1139 }
1140 return resultArray;
1141}
1142
1143//
1144// The fold functions see if an operation on a constant can be done in place,
1145// without generating run-time code.
1146//
Olli Etuaho95310b02015-06-02 17:43:38 +03001147// Returns the constant value to keep using or nullptr.
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001148//
Olli Etuaho95310b02015-06-02 17:43:38 +03001149TConstantUnion *TIntermConstantUnion::foldUnary(TOperator op, TInfoSink &infoSink)
Jamie Madillb1a85f42014-08-19 15:23:24 -04001150{
Olli Etuaho95310b02015-06-02 17:43:38 +03001151 TConstantUnion *operandArray = getUnionArrayPointer();
Jamie Madillb1a85f42014-08-19 15:23:24 -04001152
Olli Etuaho95310b02015-06-02 17:43:38 +03001153 if (!operandArray)
Arun Patolefddc2112015-04-22 13:28:10 +05301154 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001155
1156 size_t objectSize = getType().getObjectSize();
1157
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001158 if (op == EOpAny || op == EOpAll || op == EOpLength)
Arun Patole9d0b1f92015-05-20 14:27:17 +05301159 {
Olli Etuaho95310b02015-06-02 17:43:38 +03001160 // Do operations where the return type has a different number of components compared to the operand type.
1161 TConstantUnion *resultArray = nullptr;
Arun Patole9d0b1f92015-05-20 14:27:17 +05301162
Arun Patole1155ddd2015-06-05 18:04:36 +05301163 switch (op)
Arun Patole9d0b1f92015-05-20 14:27:17 +05301164 {
Arun Patole1155ddd2015-06-05 18:04:36 +05301165 case EOpAny:
Arun Patole9d0b1f92015-05-20 14:27:17 +05301166 if (getType().getBasicType() == EbtBool)
1167 {
Olli Etuaho95310b02015-06-02 17:43:38 +03001168 resultArray = new TConstantUnion();
1169 resultArray->setBConst(false);
Arun Patole9d0b1f92015-05-20 14:27:17 +05301170 for (size_t i = 0; i < objectSize; i++)
1171 {
Olli Etuaho95310b02015-06-02 17:43:38 +03001172 if (operandArray[i].getBConst())
Arun Patole9d0b1f92015-05-20 14:27:17 +05301173 {
Olli Etuaho95310b02015-06-02 17:43:38 +03001174 resultArray->setBConst(true);
Arun Patole9d0b1f92015-05-20 14:27:17 +05301175 break;
1176 }
1177 }
Arun Patole1155ddd2015-06-05 18:04:36 +05301178 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05301179 }
1180 else
1181 {
Arun Patole1155ddd2015-06-05 18:04:36 +05301182 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
Arun Patole9d0b1f92015-05-20 14:27:17 +05301183 return nullptr;
1184 }
Arun Patole1155ddd2015-06-05 18:04:36 +05301185
1186 case EOpAll:
Arun Patole9d0b1f92015-05-20 14:27:17 +05301187 if (getType().getBasicType() == EbtBool)
1188 {
Olli Etuaho95310b02015-06-02 17:43:38 +03001189 resultArray = new TConstantUnion();
1190 resultArray->setBConst(true);
Arun Patole9d0b1f92015-05-20 14:27:17 +05301191 for (size_t i = 0; i < objectSize; i++)
1192 {
Olli Etuaho95310b02015-06-02 17:43:38 +03001193 if (!operandArray[i].getBConst())
Arun Patole9d0b1f92015-05-20 14:27:17 +05301194 {
Olli Etuaho95310b02015-06-02 17:43:38 +03001195 resultArray->setBConst(false);
Arun Patole9d0b1f92015-05-20 14:27:17 +05301196 break;
1197 }
1198 }
Arun Patole1155ddd2015-06-05 18:04:36 +05301199 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05301200 }
1201 else
1202 {
Arun Patole1155ddd2015-06-05 18:04:36 +05301203 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
Arun Patole9d0b1f92015-05-20 14:27:17 +05301204 return nullptr;
1205 }
Arun Patole1155ddd2015-06-05 18:04:36 +05301206
1207 case EOpLength:
1208 if (getType().getBasicType() == EbtFloat)
1209 {
Olli Etuaho95310b02015-06-02 17:43:38 +03001210 resultArray = new TConstantUnion();
1211 resultArray->setFConst(VectorLength(operandArray, objectSize));
Arun Patole1155ddd2015-06-05 18:04:36 +05301212 break;
1213 }
1214 else
1215 {
1216 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1217 return nullptr;
1218 }
1219
1220 default:
1221 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05301222 }
Arun Patole1155ddd2015-06-05 18:04:36 +05301223
Olli Etuaho95310b02015-06-02 17:43:38 +03001224 return resultArray;
Arun Patole9d0b1f92015-05-20 14:27:17 +05301225 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04001226 else
1227 {
1228 //
Arun Patole9d0b1f92015-05-20 14:27:17 +05301229 // Do unary operations where the return type is the same as operand type.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001230 //
Olli Etuaho95310b02015-06-02 17:43:38 +03001231 TConstantUnion *resultArray = new TConstantUnion[objectSize];
Jamie Madillb1a85f42014-08-19 15:23:24 -04001232 for (size_t i = 0; i < objectSize; i++)
1233 {
1234 switch(op)
1235 {
1236 case EOpNegative:
1237 switch (getType().getBasicType())
1238 {
1239 case EbtFloat:
Olli Etuaho95310b02015-06-02 17:43:38 +03001240 resultArray[i].setFConst(-operandArray[i].getFConst());
Jamie Madillb1a85f42014-08-19 15:23:24 -04001241 break;
1242 case EbtInt:
Olli Etuaho95310b02015-06-02 17:43:38 +03001243 resultArray[i].setIConst(-operandArray[i].getIConst());
Jamie Madillb1a85f42014-08-19 15:23:24 -04001244 break;
1245 case EbtUInt:
Olli Etuaho95310b02015-06-02 17:43:38 +03001246 resultArray[i].setUConst(static_cast<unsigned int>(
1247 -static_cast<int>(operandArray[i].getUConst())));
Jamie Madillb1a85f42014-08-19 15:23:24 -04001248 break;
1249 default:
1250 infoSink.info.message(
1251 EPrefixInternalError, getLine(),
1252 "Unary operation not folded into constant");
Arun Patolefddc2112015-04-22 13:28:10 +05301253 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001254 }
1255 break;
1256
Zhenyao Mode1e00e2014-10-09 16:55:32 -07001257 case EOpPositive:
1258 switch (getType().getBasicType())
1259 {
1260 case EbtFloat:
Olli Etuaho95310b02015-06-02 17:43:38 +03001261 resultArray[i].setFConst(operandArray[i].getFConst());
Zhenyao Mode1e00e2014-10-09 16:55:32 -07001262 break;
1263 case EbtInt:
Olli Etuaho95310b02015-06-02 17:43:38 +03001264 resultArray[i].setIConst(operandArray[i].getIConst());
Zhenyao Mode1e00e2014-10-09 16:55:32 -07001265 break;
1266 case EbtUInt:
Olli Etuaho95310b02015-06-02 17:43:38 +03001267 resultArray[i].setUConst(static_cast<unsigned int>(
1268 static_cast<int>(operandArray[i].getUConst())));
Zhenyao Mode1e00e2014-10-09 16:55:32 -07001269 break;
1270 default:
1271 infoSink.info.message(
1272 EPrefixInternalError, getLine(),
1273 "Unary operation not folded into constant");
Arun Patolefddc2112015-04-22 13:28:10 +05301274 return nullptr;
Zhenyao Mode1e00e2014-10-09 16:55:32 -07001275 }
1276 break;
1277
Jamie Madillb1a85f42014-08-19 15:23:24 -04001278 case EOpLogicalNot:
1279 // this code is written for possible future use,
1280 // will not get executed currently
1281 switch (getType().getBasicType())
1282 {
1283 case EbtBool:
Olli Etuaho95310b02015-06-02 17:43:38 +03001284 resultArray[i].setBConst(!operandArray[i].getBConst());
Jamie Madillb1a85f42014-08-19 15:23:24 -04001285 break;
1286 default:
1287 infoSink.info.message(
1288 EPrefixInternalError, getLine(),
1289 "Unary operation not folded into constant");
Arun Patolefddc2112015-04-22 13:28:10 +05301290 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001291 }
1292 break;
1293
Olli Etuaho31b5fc62015-01-16 12:13:36 +02001294 case EOpBitwiseNot:
1295 switch (getType().getBasicType())
1296 {
1297 case EbtInt:
Olli Etuaho95310b02015-06-02 17:43:38 +03001298 resultArray[i].setIConst(~operandArray[i].getIConst());
Olli Etuaho31b5fc62015-01-16 12:13:36 +02001299 break;
1300 case EbtUInt:
Olli Etuaho95310b02015-06-02 17:43:38 +03001301 resultArray[i].setUConst(~operandArray[i].getUConst());
Olli Etuaho31b5fc62015-01-16 12:13:36 +02001302 break;
1303 default:
1304 infoSink.info.message(
1305 EPrefixInternalError, getLine(),
1306 "Unary operation not folded into constant");
Arun Patolefddc2112015-04-22 13:28:10 +05301307 return nullptr;
Olli Etuaho31b5fc62015-01-16 12:13:36 +02001308 }
1309 break;
1310
Arun Patole9dea48f2015-04-02 11:45:09 +05301311 case EOpRadians:
1312 if (getType().getBasicType() == EbtFloat)
1313 {
Olli Etuaho95310b02015-06-02 17:43:38 +03001314 resultArray[i].setFConst(kDegreesToRadiansMultiplier * operandArray[i].getFConst());
Arun Patole9dea48f2015-04-02 11:45:09 +05301315 break;
1316 }
1317 infoSink.info.message(
1318 EPrefixInternalError, getLine(),
1319 "Unary operation not folded into constant");
1320 return nullptr;
1321
1322 case EOpDegrees:
1323 if (getType().getBasicType() == EbtFloat)
1324 {
Olli Etuaho95310b02015-06-02 17:43:38 +03001325 resultArray[i].setFConst(kRadiansToDegreesMultiplier * operandArray[i].getFConst());
Arun Patole9dea48f2015-04-02 11:45:09 +05301326 break;
1327 }
1328 infoSink.info.message(
1329 EPrefixInternalError, getLine(),
1330 "Unary operation not folded into constant");
1331 return nullptr;
1332
1333 case EOpSin:
Olli Etuaho95310b02015-06-02 17:43:38 +03001334 if (!foldFloatTypeUnary(operandArray[i], &sinf, infoSink, &resultArray[i]))
Arun Patole9dea48f2015-04-02 11:45:09 +05301335 return nullptr;
1336 break;
1337
1338 case EOpCos:
Olli Etuaho95310b02015-06-02 17:43:38 +03001339 if (!foldFloatTypeUnary(operandArray[i], &cosf, infoSink, &resultArray[i]))
Arun Patole9dea48f2015-04-02 11:45:09 +05301340 return nullptr;
1341 break;
1342
1343 case EOpTan:
Olli Etuaho95310b02015-06-02 17:43:38 +03001344 if (!foldFloatTypeUnary(operandArray[i], &tanf, infoSink, &resultArray[i]))
Arun Patole9dea48f2015-04-02 11:45:09 +05301345 return nullptr;
1346 break;
1347
1348 case EOpAsin:
1349 // For asin(x), results are undefined if |x| > 1, we are choosing to set result to 0.
Olli Etuaho95310b02015-06-02 17:43:38 +03001350 if (getType().getBasicType() == EbtFloat && fabsf(operandArray[i].getFConst()) > 1.0f)
1351 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1352 else if (!foldFloatTypeUnary(operandArray[i], &asinf, infoSink, &resultArray[i]))
Arun Patole9dea48f2015-04-02 11:45:09 +05301353 return nullptr;
1354 break;
1355
1356 case EOpAcos:
1357 // For acos(x), results are undefined if |x| > 1, we are choosing to set result to 0.
Olli Etuaho95310b02015-06-02 17:43:38 +03001358 if (getType().getBasicType() == EbtFloat && fabsf(operandArray[i].getFConst()) > 1.0f)
1359 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1360 else if (!foldFloatTypeUnary(operandArray[i], &acosf, infoSink, &resultArray[i]))
Arun Patole9dea48f2015-04-02 11:45:09 +05301361 return nullptr;
1362 break;
1363
1364 case EOpAtan:
Olli Etuaho95310b02015-06-02 17:43:38 +03001365 if (!foldFloatTypeUnary(operandArray[i], &atanf, infoSink, &resultArray[i]))
Arun Patole9dea48f2015-04-02 11:45:09 +05301366 return nullptr;
1367 break;
1368
1369 case EOpSinh:
Olli Etuaho95310b02015-06-02 17:43:38 +03001370 if (!foldFloatTypeUnary(operandArray[i], &sinhf, infoSink, &resultArray[i]))
Arun Patole9dea48f2015-04-02 11:45:09 +05301371 return nullptr;
1372 break;
1373
1374 case EOpCosh:
Olli Etuaho95310b02015-06-02 17:43:38 +03001375 if (!foldFloatTypeUnary(operandArray[i], &coshf, infoSink, &resultArray[i]))
Arun Patole9dea48f2015-04-02 11:45:09 +05301376 return nullptr;
1377 break;
1378
1379 case EOpTanh:
Olli Etuaho95310b02015-06-02 17:43:38 +03001380 if (!foldFloatTypeUnary(operandArray[i], &tanhf, infoSink, &resultArray[i]))
Arun Patole9dea48f2015-04-02 11:45:09 +05301381 return nullptr;
1382 break;
1383
1384 case EOpAsinh:
Olli Etuaho95310b02015-06-02 17:43:38 +03001385 if (!foldFloatTypeUnary(operandArray[i], &asinhf, infoSink, &resultArray[i]))
Arun Patole9dea48f2015-04-02 11:45:09 +05301386 return nullptr;
1387 break;
1388
1389 case EOpAcosh:
1390 // For acosh(x), results are undefined if x < 1, we are choosing to set result to 0.
Olli Etuaho95310b02015-06-02 17:43:38 +03001391 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() < 1.0f)
1392 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1393 else if (!foldFloatTypeUnary(operandArray[i], &acoshf, infoSink, &resultArray[i]))
Arun Patole9dea48f2015-04-02 11:45:09 +05301394 return nullptr;
1395 break;
1396
1397 case EOpAtanh:
1398 // For atanh(x), results are undefined if |x| >= 1, we are choosing to set result to 0.
Olli Etuaho95310b02015-06-02 17:43:38 +03001399 if (getType().getBasicType() == EbtFloat && fabsf(operandArray[i].getFConst()) >= 1.0f)
1400 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1401 else if (!foldFloatTypeUnary(operandArray[i], &atanhf, infoSink, &resultArray[i]))
Arun Patole9dea48f2015-04-02 11:45:09 +05301402 return nullptr;
1403 break;
1404
Arun Patole97dc22e2015-04-06 17:35:38 +05301405 case EOpAbs:
1406 switch (getType().getBasicType())
1407 {
1408 case EbtFloat:
Olli Etuaho95310b02015-06-02 17:43:38 +03001409 resultArray[i].setFConst(fabsf(operandArray[i].getFConst()));
Arun Patole97dc22e2015-04-06 17:35:38 +05301410 break;
1411 case EbtInt:
Olli Etuaho95310b02015-06-02 17:43:38 +03001412 resultArray[i].setIConst(abs(operandArray[i].getIConst()));
Arun Patole97dc22e2015-04-06 17:35:38 +05301413 break;
1414 default:
1415 infoSink.info.message(
1416 EPrefixInternalError, getLine(),
1417 "Unary operation not folded into constant");
1418 return nullptr;
1419 }
1420 break;
1421
1422 case EOpSign:
1423 switch (getType().getBasicType())
1424 {
1425 case EbtFloat:
1426 {
Olli Etuaho95310b02015-06-02 17:43:38 +03001427 float fConst = operandArray[i].getFConst();
Arun Patole97dc22e2015-04-06 17:35:38 +05301428 float fResult = 0.0f;
1429 if (fConst > 0.0f)
1430 fResult = 1.0f;
1431 else if (fConst < 0.0f)
1432 fResult = -1.0f;
Olli Etuaho95310b02015-06-02 17:43:38 +03001433 resultArray[i].setFConst(fResult);
Arun Patole97dc22e2015-04-06 17:35:38 +05301434 }
1435 break;
1436 case EbtInt:
1437 {
Olli Etuaho95310b02015-06-02 17:43:38 +03001438 int iConst = operandArray[i].getIConst();
Arun Patole97dc22e2015-04-06 17:35:38 +05301439 int iResult = 0;
1440 if (iConst > 0)
1441 iResult = 1;
1442 else if (iConst < 0)
1443 iResult = -1;
Olli Etuaho95310b02015-06-02 17:43:38 +03001444 resultArray[i].setIConst(iResult);
Arun Patole97dc22e2015-04-06 17:35:38 +05301445 }
1446 break;
1447 default:
1448 infoSink.info.message(
1449 EPrefixInternalError, getLine(),
1450 "Unary operation not folded into constant");
1451 return nullptr;
1452 }
1453 break;
1454
1455 case EOpFloor:
Olli Etuaho95310b02015-06-02 17:43:38 +03001456 if (!foldFloatTypeUnary(operandArray[i], &floorf, infoSink, &resultArray[i]))
Arun Patole97dc22e2015-04-06 17:35:38 +05301457 return nullptr;
1458 break;
1459
1460 case EOpTrunc:
Olli Etuaho95310b02015-06-02 17:43:38 +03001461 if (!foldFloatTypeUnary(operandArray[i], &truncf, infoSink, &resultArray[i]))
Arun Patole97dc22e2015-04-06 17:35:38 +05301462 return nullptr;
1463 break;
1464
1465 case EOpRound:
Olli Etuaho95310b02015-06-02 17:43:38 +03001466 if (!foldFloatTypeUnary(operandArray[i], &roundf, infoSink, &resultArray[i]))
Arun Patole97dc22e2015-04-06 17:35:38 +05301467 return nullptr;
1468 break;
1469
1470 case EOpRoundEven:
1471 if (getType().getBasicType() == EbtFloat)
1472 {
Olli Etuaho95310b02015-06-02 17:43:38 +03001473 float x = operandArray[i].getFConst();
Arun Patole97dc22e2015-04-06 17:35:38 +05301474 float result;
1475 float fractPart = modff(x, &result);
1476 if (fabsf(fractPart) == 0.5f)
1477 result = 2.0f * roundf(x / 2.0f);
1478 else
1479 result = roundf(x);
Olli Etuaho95310b02015-06-02 17:43:38 +03001480 resultArray[i].setFConst(result);
Arun Patole97dc22e2015-04-06 17:35:38 +05301481 break;
1482 }
1483 infoSink.info.message(
1484 EPrefixInternalError, getLine(),
1485 "Unary operation not folded into constant");
1486 return nullptr;
1487
1488 case EOpCeil:
Olli Etuaho95310b02015-06-02 17:43:38 +03001489 if (!foldFloatTypeUnary(operandArray[i], &ceilf, infoSink, &resultArray[i]))
Arun Patole97dc22e2015-04-06 17:35:38 +05301490 return nullptr;
1491 break;
1492
1493 case EOpFract:
1494 if (getType().getBasicType() == EbtFloat)
1495 {
Olli Etuaho95310b02015-06-02 17:43:38 +03001496 float x = operandArray[i].getFConst();
1497 resultArray[i].setFConst(x - floorf(x));
Arun Patole97dc22e2015-04-06 17:35:38 +05301498 break;
1499 }
1500 infoSink.info.message(
1501 EPrefixInternalError, getLine(),
1502 "Unary operation not folded into constant");
1503 return nullptr;
1504
Arun Patole28eb65e2015-04-06 17:29:48 +05301505 case EOpExp:
Olli Etuaho95310b02015-06-02 17:43:38 +03001506 if (!foldFloatTypeUnary(operandArray[i], &expf, infoSink, &resultArray[i]))
Arun Patole28eb65e2015-04-06 17:29:48 +05301507 return nullptr;
1508 break;
1509
1510 case EOpLog:
1511 // For log(x), results are undefined if x <= 0, we are choosing to set result to 0.
Olli Etuaho95310b02015-06-02 17:43:38 +03001512 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() <= 0.0f)
1513 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1514 else if (!foldFloatTypeUnary(operandArray[i], &logf, infoSink, &resultArray[i]))
Arun Patole28eb65e2015-04-06 17:29:48 +05301515 return nullptr;
1516 break;
1517
1518 case EOpExp2:
Olli Etuaho95310b02015-06-02 17:43:38 +03001519 if (!foldFloatTypeUnary(operandArray[i], &exp2f, infoSink, &resultArray[i]))
Arun Patole28eb65e2015-04-06 17:29:48 +05301520 return nullptr;
1521 break;
1522
1523 case EOpLog2:
1524 // For log2(x), results are undefined if x <= 0, we are choosing to set result to 0.
1525 // 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 +03001526 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() <= 0.0f)
1527 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1528 else if (!foldFloatTypeUnary(operandArray[i], &logf, infoSink, &resultArray[i]))
Arun Patole28eb65e2015-04-06 17:29:48 +05301529 return nullptr;
1530 else
Olli Etuaho95310b02015-06-02 17:43:38 +03001531 resultArray[i].setFConst(resultArray[i].getFConst() / logf(2.0f));
Arun Patole28eb65e2015-04-06 17:29:48 +05301532 break;
1533
1534 case EOpSqrt:
1535 // For sqrt(x), results are undefined if x < 0, we are choosing to set result to 0.
Olli Etuaho95310b02015-06-02 17:43:38 +03001536 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() < 0.0f)
1537 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1538 else if (!foldFloatTypeUnary(operandArray[i], &sqrtf, infoSink, &resultArray[i]))
Arun Patole28eb65e2015-04-06 17:29:48 +05301539 return nullptr;
1540 break;
1541
1542 case EOpInverseSqrt:
1543 // There is no stdlib built-in function equavalent for GLES built-in inversesqrt(),
1544 // so getting the square root first using builtin function sqrt() and then taking its inverse.
1545 // 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 +03001546 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() <= 0.0f)
1547 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1548 else if (!foldFloatTypeUnary(operandArray[i], &sqrtf, infoSink, &resultArray[i]))
Arun Patole28eb65e2015-04-06 17:29:48 +05301549 return nullptr;
1550 else
Olli Etuaho95310b02015-06-02 17:43:38 +03001551 resultArray[i].setFConst(1.0f / resultArray[i].getFConst());
Arun Patole28eb65e2015-04-06 17:29:48 +05301552 break;
1553
Arun Patole9d0b1f92015-05-20 14:27:17 +05301554 case EOpVectorLogicalNot:
1555 if (getType().getBasicType() == EbtBool)
1556 {
Olli Etuaho95310b02015-06-02 17:43:38 +03001557 resultArray[i].setBConst(!operandArray[i].getBConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05301558 break;
1559 }
1560 infoSink.info.message(
1561 EPrefixInternalError, getLine(),
1562 "Unary operation not folded into constant");
1563 return nullptr;
1564
Arun Patole1155ddd2015-06-05 18:04:36 +05301565 case EOpNormalize:
1566 if (getType().getBasicType() == EbtFloat)
1567 {
Olli Etuaho95310b02015-06-02 17:43:38 +03001568 float x = operandArray[i].getFConst();
1569 float length = VectorLength(operandArray, objectSize);
Arun Patole1155ddd2015-06-05 18:04:36 +05301570 if (length)
Olli Etuaho95310b02015-06-02 17:43:38 +03001571 resultArray[i].setFConst(x / length);
Arun Patole1155ddd2015-06-05 18:04:36 +05301572 else
Olli Etuaho95310b02015-06-02 17:43:38 +03001573 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink,
1574 &resultArray[i]);
Arun Patole1155ddd2015-06-05 18:04:36 +05301575 break;
1576 }
1577 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1578 return nullptr;
1579
Jamie Madillb1a85f42014-08-19 15:23:24 -04001580 default:
Arun Patolefddc2112015-04-22 13:28:10 +05301581 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001582 }
1583 }
Olli Etuaho95310b02015-06-02 17:43:38 +03001584 return resultArray;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001585 }
1586}
1587
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001588bool TIntermConstantUnion::foldFloatTypeUnary(const TConstantUnion &parameter, FloatTypeUnaryFunc builtinFunc,
1589 TInfoSink &infoSink, TConstantUnion *result) const
Arun Patole9dea48f2015-04-02 11:45:09 +05301590{
1591 ASSERT(builtinFunc);
1592
1593 if (getType().getBasicType() == EbtFloat)
1594 {
1595 result->setFConst(builtinFunc(parameter.getFConst()));
1596 return true;
1597 }
1598
1599 infoSink.info.message(
1600 EPrefixInternalError, getLine(),
1601 "Unary operation not folded into constant");
1602 return false;
1603}
1604
Jamie Madillb1a85f42014-08-19 15:23:24 -04001605// static
Olli Etuahob43846e2015-06-02 18:18:57 +03001606TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *aggregate, TInfoSink &infoSink)
Arun Patole274f0702015-05-05 13:33:30 +05301607{
Olli Etuahob43846e2015-06-02 18:18:57 +03001608 TOperator op = aggregate->getOp();
Arun Patole274f0702015-05-05 13:33:30 +05301609 TIntermSequence *sequence = aggregate->getSequence();
1610 unsigned int paramsCount = sequence->size();
1611 std::vector<TConstantUnion *> unionArrays(paramsCount);
1612 std::vector<size_t> objectSizes(paramsCount);
Olli Etuahob43846e2015-06-02 18:18:57 +03001613 size_t maxObjectSize = 0;
Arun Patole274f0702015-05-05 13:33:30 +05301614 TBasicType basicType = EbtVoid;
1615 TSourceLoc loc;
1616 for (unsigned int i = 0; i < paramsCount; i++)
1617 {
1618 TIntermConstantUnion *paramConstant = (*sequence)[i]->getAsConstantUnion();
Olli Etuahob43846e2015-06-02 18:18:57 +03001619 ASSERT(paramConstant != nullptr); // Should be checked already.
Arun Patole274f0702015-05-05 13:33:30 +05301620
1621 if (i == 0)
1622 {
1623 basicType = paramConstant->getType().getBasicType();
1624 loc = paramConstant->getLine();
1625 }
1626 unionArrays[i] = paramConstant->getUnionArrayPointer();
1627 objectSizes[i] = paramConstant->getType().getObjectSize();
Olli Etuahob43846e2015-06-02 18:18:57 +03001628 if (objectSizes[i] > maxObjectSize)
1629 maxObjectSize = objectSizes[i];
Arun Patole274f0702015-05-05 13:33:30 +05301630 }
1631
Arun Patole274f0702015-05-05 13:33:30 +05301632 for (unsigned int i = 0; i < paramsCount; i++)
1633 if (objectSizes[i] != maxObjectSize)
1634 unionArrays[i] = Vectorize(*unionArrays[i], maxObjectSize);
1635
Olli Etuahob43846e2015-06-02 18:18:57 +03001636 TConstantUnion *resultArray = nullptr;
Arun Patole274f0702015-05-05 13:33:30 +05301637 if (paramsCount == 2)
1638 {
1639 //
1640 // Binary built-in
1641 //
1642 switch (op)
1643 {
Arun Patolebf790422015-05-18 17:53:04 +05301644 case EOpAtan:
1645 {
1646 if (basicType == EbtFloat)
1647 {
Olli Etuahob43846e2015-06-02 18:18:57 +03001648 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05301649 for (size_t i = 0; i < maxObjectSize; i++)
1650 {
1651 float y = unionArrays[0][i].getFConst();
1652 float x = unionArrays[1][i].getFConst();
1653 // Results are undefined if x and y are both 0.
1654 if (x == 0.0f && y == 0.0f)
Olli Etuahob43846e2015-06-02 18:18:57 +03001655 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patolebf790422015-05-18 17:53:04 +05301656 else
Olli Etuahob43846e2015-06-02 18:18:57 +03001657 resultArray[i].setFConst(atan2f(y, x));
Arun Patolebf790422015-05-18 17:53:04 +05301658 }
1659 }
1660 else
1661 UNREACHABLE();
1662 }
1663 break;
1664
1665 case EOpPow:
1666 {
1667 if (basicType == EbtFloat)
1668 {
Olli Etuahob43846e2015-06-02 18:18:57 +03001669 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05301670 for (size_t i = 0; i < maxObjectSize; i++)
1671 {
1672 float x = unionArrays[0][i].getFConst();
1673 float y = unionArrays[1][i].getFConst();
1674 // Results are undefined if x < 0.
1675 // Results are undefined if x = 0 and y <= 0.
1676 if (x < 0.0f)
Olli Etuahob43846e2015-06-02 18:18:57 +03001677 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patolebf790422015-05-18 17:53:04 +05301678 else if (x == 0.0f && y <= 0.0f)
Olli Etuahob43846e2015-06-02 18:18:57 +03001679 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patolebf790422015-05-18 17:53:04 +05301680 else
Olli Etuahob43846e2015-06-02 18:18:57 +03001681 resultArray[i].setFConst(powf(x, y));
Arun Patolebf790422015-05-18 17:53:04 +05301682 }
1683 }
1684 else
1685 UNREACHABLE();
1686 }
1687 break;
1688
1689 case EOpMod:
1690 {
1691 if (basicType == EbtFloat)
1692 {
Olli Etuahob43846e2015-06-02 18:18:57 +03001693 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05301694 for (size_t i = 0; i < maxObjectSize; i++)
1695 {
1696 float x = unionArrays[0][i].getFConst();
1697 float y = unionArrays[1][i].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03001698 resultArray[i].setFConst(x - y * floorf(x / y));
Arun Patolebf790422015-05-18 17:53:04 +05301699 }
1700 }
1701 else
1702 UNREACHABLE();
1703 }
1704 break;
1705
Arun Patole274f0702015-05-05 13:33:30 +05301706 case EOpMin:
1707 {
Olli Etuahob43846e2015-06-02 18:18:57 +03001708 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole274f0702015-05-05 13:33:30 +05301709 for (size_t i = 0; i < maxObjectSize; i++)
1710 {
1711 switch (basicType)
1712 {
1713 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03001714 resultArray[i].setFConst(std::min(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
Arun Patole274f0702015-05-05 13:33:30 +05301715 break;
1716 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03001717 resultArray[i].setIConst(std::min(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
Arun Patole274f0702015-05-05 13:33:30 +05301718 break;
1719 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03001720 resultArray[i].setUConst(std::min(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
Arun Patole274f0702015-05-05 13:33:30 +05301721 break;
1722 default:
1723 UNREACHABLE();
1724 break;
1725 }
1726 }
1727 }
1728 break;
1729
1730 case EOpMax:
1731 {
Olli Etuahob43846e2015-06-02 18:18:57 +03001732 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole274f0702015-05-05 13:33:30 +05301733 for (size_t i = 0; i < maxObjectSize; i++)
1734 {
1735 switch (basicType)
1736 {
1737 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03001738 resultArray[i].setFConst(std::max(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
Arun Patole274f0702015-05-05 13:33:30 +05301739 break;
1740 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03001741 resultArray[i].setIConst(std::max(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
Arun Patole274f0702015-05-05 13:33:30 +05301742 break;
1743 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03001744 resultArray[i].setUConst(std::max(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
Arun Patole274f0702015-05-05 13:33:30 +05301745 break;
1746 default:
1747 UNREACHABLE();
1748 break;
1749 }
1750 }
1751 }
1752 break;
1753
Arun Patolebf790422015-05-18 17:53:04 +05301754 case EOpStep:
1755 {
1756 if (basicType == EbtFloat)
1757 {
Olli Etuahob43846e2015-06-02 18:18:57 +03001758 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05301759 for (size_t i = 0; i < maxObjectSize; i++)
Olli Etuahob43846e2015-06-02 18:18:57 +03001760 resultArray[i].setFConst(unionArrays[1][i].getFConst() < unionArrays[0][i].getFConst() ? 0.0f : 1.0f);
Arun Patolebf790422015-05-18 17:53:04 +05301761 }
1762 else
1763 UNREACHABLE();
1764 }
1765 break;
1766
Arun Patole9d0b1f92015-05-20 14:27:17 +05301767 case EOpLessThan:
1768 {
Olli Etuahob43846e2015-06-02 18:18:57 +03001769 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05301770 for (size_t i = 0; i < maxObjectSize; i++)
1771 {
1772 switch (basicType)
1773 {
1774 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03001775 resultArray[i].setBConst(unionArrays[0][i].getFConst() < unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05301776 break;
1777 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03001778 resultArray[i].setBConst(unionArrays[0][i].getIConst() < unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05301779 break;
1780 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03001781 resultArray[i].setBConst(unionArrays[0][i].getUConst() < unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05301782 break;
1783 default:
1784 UNREACHABLE();
1785 break;
1786 }
1787 }
1788 }
1789 break;
1790
1791 case EOpLessThanEqual:
1792 {
Olli Etuahob43846e2015-06-02 18:18:57 +03001793 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05301794 for (size_t i = 0; i < maxObjectSize; i++)
1795 {
1796 switch (basicType)
1797 {
1798 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03001799 resultArray[i].setBConst(unionArrays[0][i].getFConst() <= unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05301800 break;
1801 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03001802 resultArray[i].setBConst(unionArrays[0][i].getIConst() <= unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05301803 break;
1804 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03001805 resultArray[i].setBConst(unionArrays[0][i].getUConst() <= unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05301806 break;
1807 default:
1808 UNREACHABLE();
1809 break;
1810 }
1811 }
1812 }
1813 break;
1814
1815 case EOpGreaterThan:
1816 {
Olli Etuahob43846e2015-06-02 18:18:57 +03001817 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05301818 for (size_t i = 0; i < maxObjectSize; i++)
1819 {
1820 switch (basicType)
1821 {
1822 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03001823 resultArray[i].setBConst(unionArrays[0][i].getFConst() > unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05301824 break;
1825 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03001826 resultArray[i].setBConst(unionArrays[0][i].getIConst() > unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05301827 break;
1828 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03001829 resultArray[i].setBConst(unionArrays[0][i].getUConst() > unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05301830 break;
1831 default:
1832 UNREACHABLE();
1833 break;
Olli Etuahob43846e2015-06-02 18:18:57 +03001834 }
1835 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05301836 }
1837 break;
1838
1839 case EOpGreaterThanEqual:
1840 {
Olli Etuahob43846e2015-06-02 18:18:57 +03001841 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05301842 for (size_t i = 0; i < maxObjectSize; i++)
1843 {
1844 switch (basicType)
1845 {
1846 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03001847 resultArray[i].setBConst(unionArrays[0][i].getFConst() >= unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05301848 break;
1849 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03001850 resultArray[i].setBConst(unionArrays[0][i].getIConst() >= unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05301851 break;
1852 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03001853 resultArray[i].setBConst(unionArrays[0][i].getUConst() >= unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05301854 break;
1855 default:
1856 UNREACHABLE();
1857 break;
1858 }
1859 }
1860 }
1861 break;
1862
1863 case EOpVectorEqual:
1864 {
Olli Etuahob43846e2015-06-02 18:18:57 +03001865 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05301866 for (size_t i = 0; i < maxObjectSize; i++)
1867 {
1868 switch (basicType)
1869 {
1870 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03001871 resultArray[i].setBConst(unionArrays[0][i].getFConst() == unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05301872 break;
1873 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03001874 resultArray[i].setBConst(unionArrays[0][i].getIConst() == unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05301875 break;
1876 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03001877 resultArray[i].setBConst(unionArrays[0][i].getUConst() == unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05301878 break;
1879 case EbtBool:
Olli Etuahob43846e2015-06-02 18:18:57 +03001880 resultArray[i].setBConst(unionArrays[0][i].getBConst() == unionArrays[1][i].getBConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05301881 break;
1882 default:
1883 UNREACHABLE();
1884 break;
1885 }
1886 }
1887 }
1888 break;
1889
1890 case EOpVectorNotEqual:
1891 {
Olli Etuahob43846e2015-06-02 18:18:57 +03001892 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05301893 for (size_t i = 0; i < maxObjectSize; i++)
1894 {
1895 switch (basicType)
1896 {
1897 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03001898 resultArray[i].setBConst(unionArrays[0][i].getFConst() != unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05301899 break;
1900 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03001901 resultArray[i].setBConst(unionArrays[0][i].getIConst() != unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05301902 break;
1903 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03001904 resultArray[i].setBConst(unionArrays[0][i].getUConst() != unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05301905 break;
1906 case EbtBool:
Olli Etuahob43846e2015-06-02 18:18:57 +03001907 resultArray[i].setBConst(unionArrays[0][i].getBConst() != unionArrays[1][i].getBConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05301908 break;
1909 default:
1910 UNREACHABLE();
1911 break;
1912 }
1913 }
1914 }
1915 break;
1916
Arun Patole1155ddd2015-06-05 18:04:36 +05301917 case EOpDistance:
1918 if (basicType == EbtFloat)
1919 {
1920 TConstantUnion *distanceArray = new TConstantUnion[maxObjectSize];
Olli Etuahob43846e2015-06-02 18:18:57 +03001921 resultArray = new TConstantUnion();
Arun Patole1155ddd2015-06-05 18:04:36 +05301922 for (size_t i = 0; i < maxObjectSize; i++)
1923 {
1924 float x = unionArrays[0][i].getFConst();
1925 float y = unionArrays[1][i].getFConst();
1926 distanceArray[i].setFConst(x - y);
1927 }
Olli Etuahob43846e2015-06-02 18:18:57 +03001928 resultArray->setFConst(VectorLength(distanceArray, maxObjectSize));
Arun Patole1155ddd2015-06-05 18:04:36 +05301929 }
1930 else
1931 UNREACHABLE();
1932 break;
1933
1934 case EOpDot:
Olli Etuahob43846e2015-06-02 18:18:57 +03001935
Arun Patole1155ddd2015-06-05 18:04:36 +05301936 if (basicType == EbtFloat)
1937 {
Olli Etuahob43846e2015-06-02 18:18:57 +03001938 resultArray = new TConstantUnion();
1939 resultArray->setFConst(VectorDotProduct(unionArrays[0], unionArrays[1], maxObjectSize));
Arun Patole1155ddd2015-06-05 18:04:36 +05301940 }
1941 else
1942 UNREACHABLE();
1943 break;
1944
1945 case EOpCross:
1946 if (basicType == EbtFloat && maxObjectSize == 3)
1947 {
Olli Etuahob43846e2015-06-02 18:18:57 +03001948 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05301949 float x0 = unionArrays[0][0].getFConst();
1950 float x1 = unionArrays[0][1].getFConst();
1951 float x2 = unionArrays[0][2].getFConst();
1952 float y0 = unionArrays[1][0].getFConst();
1953 float y1 = unionArrays[1][1].getFConst();
1954 float y2 = unionArrays[1][2].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03001955 resultArray[0].setFConst(x1 * y2 - y1 * x2);
1956 resultArray[1].setFConst(x2 * y0 - y2 * x0);
1957 resultArray[2].setFConst(x0 * y1 - y0 * x1);
Arun Patole1155ddd2015-06-05 18:04:36 +05301958 }
1959 else
1960 UNREACHABLE();
1961 break;
1962
1963 case EOpReflect:
1964 if (basicType == EbtFloat)
1965 {
1966 // genType reflect (genType I, genType N) :
1967 // For the incident vector I and surface orientation N, returns the reflection direction:
1968 // I - 2 * dot(N, I) * N.
Olli Etuahob43846e2015-06-02 18:18:57 +03001969 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05301970 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
1971 for (size_t i = 0; i < maxObjectSize; i++)
1972 {
1973 float result = unionArrays[0][i].getFConst() -
1974 2.0f * dotProduct * unionArrays[1][i].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03001975 resultArray[i].setFConst(result);
Arun Patole1155ddd2015-06-05 18:04:36 +05301976 }
1977 }
1978 else
1979 UNREACHABLE();
1980 break;
1981
Arun Patole274f0702015-05-05 13:33:30 +05301982 default:
1983 UNREACHABLE();
1984 // TODO: Add constant folding support for other built-in operations that take 2 parameters and not handled above.
1985 return nullptr;
1986 }
1987 }
1988 else if (paramsCount == 3)
1989 {
1990 //
1991 // Ternary built-in
1992 //
1993 switch (op)
1994 {
1995 case EOpClamp:
1996 {
Olli Etuahob43846e2015-06-02 18:18:57 +03001997 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole274f0702015-05-05 13:33:30 +05301998 for (size_t i = 0; i < maxObjectSize; i++)
1999 {
2000 switch (basicType)
2001 {
2002 case EbtFloat:
2003 {
2004 float x = unionArrays[0][i].getFConst();
2005 float min = unionArrays[1][i].getFConst();
2006 float max = unionArrays[2][i].getFConst();
2007 // Results are undefined if min > max.
2008 if (min > max)
Olli Etuahob43846e2015-06-02 18:18:57 +03002009 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302010 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002011 resultArray[i].setFConst(gl::clamp(x, min, max));
Arun Patole274f0702015-05-05 13:33:30 +05302012 }
2013 break;
2014 case EbtInt:
2015 {
2016 int x = unionArrays[0][i].getIConst();
2017 int min = unionArrays[1][i].getIConst();
2018 int max = unionArrays[2][i].getIConst();
2019 // Results are undefined if min > max.
2020 if (min > max)
Olli Etuahob43846e2015-06-02 18:18:57 +03002021 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302022 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002023 resultArray[i].setIConst(gl::clamp(x, min, max));
Arun Patole274f0702015-05-05 13:33:30 +05302024 }
2025 break;
2026 case EbtUInt:
2027 {
2028 unsigned int x = unionArrays[0][i].getUConst();
2029 unsigned int min = unionArrays[1][i].getUConst();
2030 unsigned int max = unionArrays[2][i].getUConst();
2031 // Results are undefined if min > max.
2032 if (min > max)
Olli Etuahob43846e2015-06-02 18:18:57 +03002033 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302034 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002035 resultArray[i].setUConst(gl::clamp(x, min, max));
Arun Patole274f0702015-05-05 13:33:30 +05302036 }
2037 break;
2038 default:
2039 UNREACHABLE();
2040 break;
2041 }
2042 }
2043 }
2044 break;
2045
Arun Patolebf790422015-05-18 17:53:04 +05302046 case EOpMix:
2047 {
2048 if (basicType == EbtFloat)
2049 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002050 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05302051 for (size_t i = 0; i < maxObjectSize; i++)
2052 {
2053 float x = unionArrays[0][i].getFConst();
2054 float y = unionArrays[1][i].getFConst();
2055 TBasicType type = (*sequence)[2]->getAsTyped()->getType().getBasicType();
2056 if (type == EbtFloat)
2057 {
2058 // Returns the linear blend of x and y, i.e., x * (1 - a) + y * a.
2059 float a = unionArrays[2][i].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002060 resultArray[i].setFConst(x * (1.0f - a) + y * a);
Arun Patolebf790422015-05-18 17:53:04 +05302061 }
2062 else // 3rd parameter is EbtBool
2063 {
2064 ASSERT(type == EbtBool);
2065 // Selects which vector each returned component comes from.
2066 // For a component of a that is false, the corresponding component of x is returned.
2067 // For a component of a that is true, the corresponding component of y is returned.
2068 bool a = unionArrays[2][i].getBConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002069 resultArray[i].setFConst(a ? y : x);
Arun Patolebf790422015-05-18 17:53:04 +05302070 }
2071 }
2072 }
2073 else
2074 UNREACHABLE();
2075 }
2076 break;
2077
2078 case EOpSmoothStep:
2079 {
2080 if (basicType == EbtFloat)
2081 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002082 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05302083 for (size_t i = 0; i < maxObjectSize; i++)
2084 {
2085 float edge0 = unionArrays[0][i].getFConst();
2086 float edge1 = unionArrays[1][i].getFConst();
2087 float x = unionArrays[2][i].getFConst();
2088 // Results are undefined if edge0 >= edge1.
2089 if (edge0 >= edge1)
2090 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002091 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patolebf790422015-05-18 17:53:04 +05302092 }
2093 else
2094 {
2095 // Returns 0.0 if x <= edge0 and 1.0 if x >= edge1 and performs smooth
2096 // Hermite interpolation between 0 and 1 when edge0 < x < edge1.
2097 float t = gl::clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f);
Olli Etuahob43846e2015-06-02 18:18:57 +03002098 resultArray[i].setFConst(t * t * (3.0f - 2.0f * t));
Arun Patolebf790422015-05-18 17:53:04 +05302099 }
2100 }
2101 }
2102 else
2103 UNREACHABLE();
2104 }
2105 break;
2106
Arun Patole1155ddd2015-06-05 18:04:36 +05302107 case EOpFaceForward:
2108 if (basicType == EbtFloat)
2109 {
2110 // genType faceforward(genType N, genType I, genType Nref) :
2111 // If dot(Nref, I) < 0 return N, otherwise return -N.
Olli Etuahob43846e2015-06-02 18:18:57 +03002112 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302113 float dotProduct = VectorDotProduct(unionArrays[2], unionArrays[1], maxObjectSize);
2114 for (size_t i = 0; i < maxObjectSize; i++)
2115 {
2116 if (dotProduct < 0)
Olli Etuahob43846e2015-06-02 18:18:57 +03002117 resultArray[i].setFConst(unionArrays[0][i].getFConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05302118 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002119 resultArray[i].setFConst(-unionArrays[0][i].getFConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05302120 }
2121 }
2122 else
2123 UNREACHABLE();
2124 break;
2125
2126 case EOpRefract:
2127 if (basicType == EbtFloat)
2128 {
2129 // genType refract(genType I, genType N, float eta) :
2130 // For the incident vector I and surface normal N, and the ratio of indices of refraction eta,
2131 // return the refraction vector. The result is computed by
2132 // k = 1.0 - eta * eta * (1.0 - dot(N, I) * dot(N, I))
2133 // if (k < 0.0)
2134 // return genType(0.0)
2135 // else
2136 // return eta * I - (eta * dot(N, I) + sqrt(k)) * N
Olli Etuahob43846e2015-06-02 18:18:57 +03002137 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302138 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
2139 for (size_t i = 0; i < maxObjectSize; i++)
2140 {
2141 float eta = unionArrays[2][i].getFConst();
2142 float k = 1.0f - eta * eta * (1.0f - dotProduct * dotProduct);
2143 if (k < 0.0f)
Olli Etuahob43846e2015-06-02 18:18:57 +03002144 resultArray[i].setFConst(0.0f);
Arun Patole1155ddd2015-06-05 18:04:36 +05302145 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002146 resultArray[i].setFConst(eta * unionArrays[0][i].getFConst() -
Arun Patole1155ddd2015-06-05 18:04:36 +05302147 (eta * dotProduct + sqrtf(k)) * unionArrays[1][i].getFConst());
2148 }
2149 }
2150 else
2151 UNREACHABLE();
2152 break;
2153
Arun Patole274f0702015-05-05 13:33:30 +05302154 default:
2155 UNREACHABLE();
2156 // TODO: Add constant folding support for other built-in operations that take 3 parameters and not handled above.
2157 return nullptr;
2158 }
2159 }
Olli Etuahob43846e2015-06-02 18:18:57 +03002160 return resultArray;
Arun Patole274f0702015-05-05 13:33:30 +05302161}
2162
2163// static
Jamie Madillb1a85f42014-08-19 15:23:24 -04002164TString TIntermTraverser::hash(const TString &name, ShHashFunction64 hashFunction)
2165{
2166 if (hashFunction == NULL || name.empty())
2167 return name;
2168 khronos_uint64_t number = (*hashFunction)(name.c_str(), name.length());
2169 TStringStream stream;
2170 stream << HASHED_NAME_PREFIX << std::hex << number;
2171 TString hashedName = stream.str();
2172 return hashedName;
2173}
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002174
2175void TIntermTraverser::updateTree()
2176{
Olli Etuahoa6f22092015-05-08 18:31:10 +03002177 for (size_t ii = 0; ii < mInsertions.size(); ++ii)
2178 {
2179 const NodeInsertMultipleEntry &insertion = mInsertions[ii];
2180 ASSERT(insertion.parent);
2181 bool inserted = insertion.parent->insertChildNodes(insertion.position, insertion.insertions);
2182 ASSERT(inserted);
2183 UNUSED_ASSERTION_VARIABLE(inserted);
2184 }
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002185 for (size_t ii = 0; ii < mReplacements.size(); ++ii)
2186 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03002187 const NodeUpdateEntry &replacement = mReplacements[ii];
2188 ASSERT(replacement.parent);
2189 bool replaced = replacement.parent->replaceChildNode(
2190 replacement.original, replacement.replacement);
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002191 ASSERT(replaced);
Olli Etuahod57e0db2015-04-24 15:05:08 +03002192 UNUSED_ASSERTION_VARIABLE(replaced);
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002193
Olli Etuahocd94ef92015-04-16 19:18:10 +03002194 if (!replacement.originalBecomesChildOfReplacement)
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002195 {
2196 // In AST traversing, a parent is visited before its children.
Olli Etuahocd94ef92015-04-16 19:18:10 +03002197 // After we replace a node, if its immediate child is to
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002198 // be replaced, we need to make sure we don't update the replaced
2199 // node; instead, we update the replacement node.
2200 for (size_t jj = ii + 1; jj < mReplacements.size(); ++jj)
2201 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03002202 NodeUpdateEntry &replacement2 = mReplacements[jj];
2203 if (replacement2.parent == replacement.original)
2204 replacement2.parent = replacement.replacement;
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002205 }
2206 }
2207 }
Olli Etuahofc0e2bc2015-04-16 13:39:56 +03002208 for (size_t ii = 0; ii < mMultiReplacements.size(); ++ii)
2209 {
2210 const NodeReplaceWithMultipleEntry &replacement = mMultiReplacements[ii];
2211 ASSERT(replacement.parent);
2212 bool replaced = replacement.parent->replaceChildNodeWithMultiple(
2213 replacement.original, replacement.replacements);
2214 ASSERT(replaced);
Olli Etuahod57e0db2015-04-24 15:05:08 +03002215 UNUSED_ASSERTION_VARIABLE(replaced);
Olli Etuahofc0e2bc2015-04-16 13:39:56 +03002216 }
Olli Etuahod4f303e2015-05-20 17:09:06 +03002217
2218 mInsertions.clear();
2219 mReplacements.clear();
2220 mMultiReplacements.clear();
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002221}