blob: dc52a2808f2bb88d9acb3166193d6405cba099cb [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
Jamie Madillb1a85f42014-08-19 15:23:24 -0400190} // namespace anonymous
191
192
193////////////////////////////////////////////////////////////////
194//
195// Member functions of the nodes used for building the tree.
196//
197////////////////////////////////////////////////////////////////
198
Olli Etuahod2a67b92014-10-21 16:42:57 +0300199void TIntermTyped::setTypePreservePrecision(const TType &t)
200{
201 TPrecision precision = getPrecision();
202 mType = t;
203 ASSERT(mType.getBasicType() != EbtBool || precision == EbpUndefined);
204 mType.setPrecision(precision);
205}
206
Jamie Madillb1a85f42014-08-19 15:23:24 -0400207#define REPLACE_IF_IS(node, type, original, replacement) \
208 if (node == original) { \
209 node = static_cast<type *>(replacement); \
210 return true; \
211 }
212
213bool TIntermLoop::replaceChildNode(
214 TIntermNode *original, TIntermNode *replacement)
215{
216 REPLACE_IF_IS(mInit, TIntermNode, original, replacement);
217 REPLACE_IF_IS(mCond, TIntermTyped, original, replacement);
218 REPLACE_IF_IS(mExpr, TIntermTyped, original, replacement);
219 REPLACE_IF_IS(mBody, TIntermNode, original, replacement);
220 return false;
221}
222
Jamie Madillb1a85f42014-08-19 15:23:24 -0400223bool TIntermBranch::replaceChildNode(
224 TIntermNode *original, TIntermNode *replacement)
225{
226 REPLACE_IF_IS(mExpression, TIntermTyped, original, replacement);
227 return false;
228}
229
Jamie Madillb1a85f42014-08-19 15:23:24 -0400230bool TIntermBinary::replaceChildNode(
231 TIntermNode *original, TIntermNode *replacement)
232{
233 REPLACE_IF_IS(mLeft, TIntermTyped, original, replacement);
234 REPLACE_IF_IS(mRight, TIntermTyped, original, replacement);
235 return false;
236}
237
Jamie Madillb1a85f42014-08-19 15:23:24 -0400238bool TIntermUnary::replaceChildNode(
239 TIntermNode *original, TIntermNode *replacement)
240{
241 REPLACE_IF_IS(mOperand, TIntermTyped, original, replacement);
242 return false;
243}
244
Jamie Madillb1a85f42014-08-19 15:23:24 -0400245bool TIntermAggregate::replaceChildNode(
246 TIntermNode *original, TIntermNode *replacement)
247{
248 for (size_t ii = 0; ii < mSequence.size(); ++ii)
249 {
250 REPLACE_IF_IS(mSequence[ii], TIntermNode, original, replacement);
251 }
252 return false;
253}
254
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300255bool TIntermAggregate::replaceChildNodeWithMultiple(TIntermNode *original, TIntermSequence replacements)
256{
257 for (auto it = mSequence.begin(); it < mSequence.end(); ++it)
258 {
259 if (*it == original)
260 {
261 it = mSequence.erase(it);
Olli Etuaho8fee0ab2015-04-23 14:52:46 +0300262 mSequence.insert(it, replacements.begin(), replacements.end());
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300263 return true;
264 }
265 }
266 return false;
267}
268
Olli Etuahoa6f22092015-05-08 18:31:10 +0300269bool TIntermAggregate::insertChildNodes(TIntermSequence::size_type position, TIntermSequence insertions)
270{
271 TIntermSequence::size_type itPosition = 0;
272 for (auto it = mSequence.begin(); it < mSequence.end(); ++it)
273 {
274 if (itPosition == position)
275 {
276 mSequence.insert(it, insertions.begin(), insertions.end());
277 return true;
278 }
279 ++itPosition;
280 }
281 return false;
282}
283
Olli Etuahod2a67b92014-10-21 16:42:57 +0300284void TIntermAggregate::setPrecisionFromChildren()
285{
286 if (getBasicType() == EbtBool)
287 {
288 mType.setPrecision(EbpUndefined);
289 return;
290 }
291
292 TPrecision precision = EbpUndefined;
293 TIntermSequence::iterator childIter = mSequence.begin();
294 while (childIter != mSequence.end())
295 {
296 TIntermTyped *typed = (*childIter)->getAsTyped();
297 if (typed)
298 precision = GetHigherPrecision(typed->getPrecision(), precision);
299 ++childIter;
300 }
301 mType.setPrecision(precision);
302}
303
304void TIntermAggregate::setBuiltInFunctionPrecision()
305{
306 // All built-ins returning bool should be handled as ops, not functions.
307 ASSERT(getBasicType() != EbtBool);
308
309 TPrecision precision = EbpUndefined;
310 TIntermSequence::iterator childIter = mSequence.begin();
311 while (childIter != mSequence.end())
312 {
313 TIntermTyped *typed = (*childIter)->getAsTyped();
314 // ESSL spec section 8: texture functions get their precision from the sampler.
315 if (typed && IsSampler(typed->getBasicType()))
316 {
317 precision = typed->getPrecision();
318 break;
319 }
320 ++childIter;
321 }
322 // ESSL 3.0 spec section 8: textureSize always gets highp precision.
323 // All other functions that take a sampler are assumed to be texture functions.
324 if (mName.find("textureSize") == 0)
325 mType.setPrecision(EbpHigh);
326 else
327 mType.setPrecision(precision);
328}
329
Jamie Madillb1a85f42014-08-19 15:23:24 -0400330bool TIntermSelection::replaceChildNode(
331 TIntermNode *original, TIntermNode *replacement)
332{
333 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
334 REPLACE_IF_IS(mTrueBlock, TIntermNode, original, replacement);
335 REPLACE_IF_IS(mFalseBlock, TIntermNode, original, replacement);
336 return false;
337}
338
Olli Etuahoa3a36662015-02-17 13:46:51 +0200339bool TIntermSwitch::replaceChildNode(
340 TIntermNode *original, TIntermNode *replacement)
341{
342 REPLACE_IF_IS(mInit, TIntermTyped, original, replacement);
343 REPLACE_IF_IS(mStatementList, TIntermAggregate, original, replacement);
344 return false;
345}
346
347bool TIntermCase::replaceChildNode(
348 TIntermNode *original, TIntermNode *replacement)
349{
350 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
351 return false;
352}
353
Jamie Madillb1a85f42014-08-19 15:23:24 -0400354//
355// Say whether or not an operation node changes the value of a variable.
356//
357bool TIntermOperator::isAssignment() const
358{
359 switch (mOp)
360 {
361 case EOpPostIncrement:
362 case EOpPostDecrement:
363 case EOpPreIncrement:
364 case EOpPreDecrement:
365 case EOpAssign:
366 case EOpAddAssign:
367 case EOpSubAssign:
368 case EOpMulAssign:
369 case EOpVectorTimesMatrixAssign:
370 case EOpVectorTimesScalarAssign:
371 case EOpMatrixTimesScalarAssign:
372 case EOpMatrixTimesMatrixAssign:
373 case EOpDivAssign:
Olli Etuahoff805cc2015-02-13 10:59:34 +0200374 case EOpIModAssign:
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200375 case EOpBitShiftLeftAssign:
376 case EOpBitShiftRightAssign:
377 case EOpBitwiseAndAssign:
378 case EOpBitwiseXorAssign:
379 case EOpBitwiseOrAssign:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400380 return true;
381 default:
382 return false;
383 }
384}
385
Olli Etuaho8f76bcc2015-06-02 13:54:20 +0300386bool TIntermOperator::isMultiplication() const
387{
388 switch (mOp)
389 {
390 case EOpMul:
391 case EOpMatrixTimesMatrix:
392 case EOpMatrixTimesVector:
393 case EOpMatrixTimesScalar:
394 case EOpVectorTimesMatrix:
395 case EOpVectorTimesScalar:
396 return true;
397 default:
398 return false;
399 }
400}
401
Jamie Madillb1a85f42014-08-19 15:23:24 -0400402//
403// returns true if the operator is for one of the constructors
404//
405bool TIntermOperator::isConstructor() const
406{
407 switch (mOp)
408 {
409 case EOpConstructVec2:
410 case EOpConstructVec3:
411 case EOpConstructVec4:
412 case EOpConstructMat2:
413 case EOpConstructMat3:
414 case EOpConstructMat4:
415 case EOpConstructFloat:
416 case EOpConstructIVec2:
417 case EOpConstructIVec3:
418 case EOpConstructIVec4:
419 case EOpConstructInt:
420 case EOpConstructUVec2:
421 case EOpConstructUVec3:
422 case EOpConstructUVec4:
423 case EOpConstructUInt:
424 case EOpConstructBVec2:
425 case EOpConstructBVec3:
426 case EOpConstructBVec4:
427 case EOpConstructBool:
428 case EOpConstructStruct:
429 return true;
430 default:
431 return false;
432 }
433}
434
435//
436// Make sure the type of a unary operator is appropriate for its
437// combination of operation and operand type.
438//
Olli Etuahof6c694b2015-03-26 14:50:53 +0200439void TIntermUnary::promote(const TType *funcReturnType)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400440{
441 switch (mOp)
442 {
Olli Etuahodca3e792015-03-26 13:24:04 +0200443 case EOpFloatBitsToInt:
444 case EOpFloatBitsToUint:
Olli Etuahoe8d2c072015-01-08 16:33:54 +0200445 case EOpIntBitsToFloat:
446 case EOpUintBitsToFloat:
Olli Etuahodca3e792015-03-26 13:24:04 +0200447 case EOpPackSnorm2x16:
448 case EOpPackUnorm2x16:
449 case EOpPackHalf2x16:
Olli Etuaho7700ff62015-01-15 12:16:29 +0200450 case EOpUnpackSnorm2x16:
451 case EOpUnpackUnorm2x16:
Olli Etuahodca3e792015-03-26 13:24:04 +0200452 mType.setPrecision(EbpHigh);
Arun Patole6b19d762015-02-19 09:40:39 +0530453 break;
Olli Etuahodca3e792015-03-26 13:24:04 +0200454 case EOpUnpackHalf2x16:
455 mType.setPrecision(EbpMedium);
456 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400457 default:
Olli Etuahodca3e792015-03-26 13:24:04 +0200458 setType(mOperand->getType());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400459 }
460
Olli Etuahof6c694b2015-03-26 14:50:53 +0200461 if (funcReturnType != nullptr)
462 {
463 if (funcReturnType->getBasicType() == EbtBool)
464 {
465 // Bool types should not have precision.
466 setType(*funcReturnType);
467 }
468 else
469 {
470 // Precision of the node has been set based on the operand.
471 setTypePreservePrecision(*funcReturnType);
472 }
473 }
474
Jamie Madillb1a85f42014-08-19 15:23:24 -0400475 mType.setQualifier(EvqTemporary);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400476}
477
478//
479// Establishes the type of the resultant operation, as well as
480// makes the operator the correct one for the operands.
481//
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200482// For lots of operations it should already be established that the operand
483// combination is valid, but returns false if operator can't work on operands.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400484//
485bool TIntermBinary::promote(TInfoSink &infoSink)
486{
Olli Etuahoe79904c2015-03-18 16:56:42 +0200487 ASSERT(mLeft->isArray() == mRight->isArray());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400488
Jamie Madillb1a85f42014-08-19 15:23:24 -0400489 //
490 // Base assumption: just make the type the same as the left
491 // operand. Then only deviations from this need be coded.
492 //
493 setType(mLeft->getType());
494
495 // The result gets promoted to the highest precision.
496 TPrecision higherPrecision = GetHigherPrecision(
497 mLeft->getPrecision(), mRight->getPrecision());
498 getTypePointer()->setPrecision(higherPrecision);
499
500 // Binary operations results in temporary variables unless both
501 // operands are const.
502 if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst)
503 {
504 getTypePointer()->setQualifier(EvqTemporary);
505 }
506
507 const int nominalSize =
508 std::max(mLeft->getNominalSize(), mRight->getNominalSize());
509
510 //
511 // All scalars or structs. Code after this test assumes this case is removed!
512 //
513 if (nominalSize == 1)
514 {
515 switch (mOp)
516 {
517 //
518 // Promote to conditional
519 //
520 case EOpEqual:
521 case EOpNotEqual:
522 case EOpLessThan:
523 case EOpGreaterThan:
524 case EOpLessThanEqual:
525 case EOpGreaterThanEqual:
526 setType(TType(EbtBool, EbpUndefined));
527 break;
528
529 //
530 // And and Or operate on conditionals
531 //
532 case EOpLogicalAnd:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200533 case EOpLogicalXor:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400534 case EOpLogicalOr:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200535 ASSERT(mLeft->getBasicType() == EbtBool && mRight->getBasicType() == EbtBool);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400536 setType(TType(EbtBool, EbpUndefined));
537 break;
538
539 default:
540 break;
541 }
542 return true;
543 }
544
545 // If we reach here, at least one of the operands is vector or matrix.
546 // The other operand could be a scalar, vector, or matrix.
547 // Can these two operands be combined?
548 //
549 TBasicType basicType = mLeft->getBasicType();
550 switch (mOp)
551 {
552 case EOpMul:
553 if (!mLeft->isMatrix() && mRight->isMatrix())
554 {
555 if (mLeft->isVector())
556 {
557 mOp = EOpVectorTimesMatrix;
558 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700559 static_cast<unsigned char>(mRight->getCols()), 1));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400560 }
561 else
562 {
563 mOp = EOpMatrixTimesScalar;
564 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700565 static_cast<unsigned char>(mRight->getCols()), static_cast<unsigned char>(mRight->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400566 }
567 }
568 else if (mLeft->isMatrix() && !mRight->isMatrix())
569 {
570 if (mRight->isVector())
571 {
572 mOp = EOpMatrixTimesVector;
573 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700574 static_cast<unsigned char>(mLeft->getRows()), 1));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400575 }
576 else
577 {
578 mOp = EOpMatrixTimesScalar;
579 }
580 }
581 else if (mLeft->isMatrix() && mRight->isMatrix())
582 {
583 mOp = EOpMatrixTimesMatrix;
584 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700585 static_cast<unsigned char>(mRight->getCols()), static_cast<unsigned char>(mLeft->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400586 }
587 else if (!mLeft->isMatrix() && !mRight->isMatrix())
588 {
589 if (mLeft->isVector() && mRight->isVector())
590 {
591 // leave as component product
592 }
593 else if (mLeft->isVector() || mRight->isVector())
594 {
595 mOp = EOpVectorTimesScalar;
596 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700597 static_cast<unsigned char>(nominalSize), 1));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400598 }
599 }
600 else
601 {
602 infoSink.info.message(EPrefixInternalError, getLine(),
603 "Missing elses");
604 return false;
605 }
606
607 if (!ValidateMultiplication(mOp, mLeft->getType(), mRight->getType()))
608 {
609 return false;
610 }
611 break;
612
613 case EOpMulAssign:
614 if (!mLeft->isMatrix() && mRight->isMatrix())
615 {
616 if (mLeft->isVector())
617 {
618 mOp = EOpVectorTimesMatrixAssign;
619 }
620 else
621 {
622 return false;
623 }
624 }
625 else if (mLeft->isMatrix() && !mRight->isMatrix())
626 {
627 if (mRight->isVector())
628 {
629 return false;
630 }
631 else
632 {
633 mOp = EOpMatrixTimesScalarAssign;
634 }
635 }
636 else if (mLeft->isMatrix() && mRight->isMatrix())
637 {
638 mOp = EOpMatrixTimesMatrixAssign;
639 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700640 static_cast<unsigned char>(mRight->getCols()), static_cast<unsigned char>(mLeft->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400641 }
642 else if (!mLeft->isMatrix() && !mRight->isMatrix())
643 {
644 if (mLeft->isVector() && mRight->isVector())
645 {
646 // leave as component product
647 }
648 else if (mLeft->isVector() || mRight->isVector())
649 {
650 if (!mLeft->isVector())
651 return false;
652 mOp = EOpVectorTimesScalarAssign;
653 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700654 static_cast<unsigned char>(mLeft->getNominalSize()), 1));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400655 }
656 }
657 else
658 {
659 infoSink.info.message(EPrefixInternalError, getLine(),
660 "Missing elses");
661 return false;
662 }
663
664 if (!ValidateMultiplication(mOp, mLeft->getType(), mRight->getType()))
665 {
666 return false;
667 }
668 break;
669
670 case EOpAssign:
671 case EOpInitialize:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200672 // No more additional checks are needed.
673 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
674 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
675 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400676 case EOpAdd:
677 case EOpSub:
678 case EOpDiv:
Olli Etuahoff805cc2015-02-13 10:59:34 +0200679 case EOpIMod:
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200680 case EOpBitShiftLeft:
681 case EOpBitShiftRight:
682 case EOpBitwiseAnd:
683 case EOpBitwiseXor:
684 case EOpBitwiseOr:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400685 case EOpAddAssign:
686 case EOpSubAssign:
687 case EOpDivAssign:
Olli Etuahoff805cc2015-02-13 10:59:34 +0200688 case EOpIModAssign:
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200689 case EOpBitShiftLeftAssign:
690 case EOpBitShiftRightAssign:
691 case EOpBitwiseAndAssign:
692 case EOpBitwiseXorAssign:
693 case EOpBitwiseOrAssign:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400694 if ((mLeft->isMatrix() && mRight->isVector()) ||
695 (mLeft->isVector() && mRight->isMatrix()))
696 {
697 return false;
698 }
699
700 // Are the sizes compatible?
701 if (mLeft->getNominalSize() != mRight->getNominalSize() ||
702 mLeft->getSecondarySize() != mRight->getSecondarySize())
703 {
Olli Etuaho6c850472014-12-02 16:23:17 +0200704 // If the nominal sizes of operands do not match:
705 // One of them must be a scalar.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400706 if (!mLeft->isScalar() && !mRight->isScalar())
707 return false;
708
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200709 // In the case of compound assignment other than multiply-assign,
710 // the right side needs to be a scalar. Otherwise a vector/matrix
711 // would be assigned to a scalar. A scalar can't be shifted by a
712 // vector either.
Olli Etuaho6c850472014-12-02 16:23:17 +0200713 if (!mRight->isScalar() &&
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200714 (isAssignment() ||
715 mOp == EOpBitShiftLeft ||
716 mOp == EOpBitShiftRight))
Olli Etuaho6c850472014-12-02 16:23:17 +0200717 return false;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400718 }
719
720 {
721 const int secondarySize = std::max(
722 mLeft->getSecondarySize(), mRight->getSecondarySize());
723 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700724 static_cast<unsigned char>(nominalSize), static_cast<unsigned char>(secondarySize)));
Olli Etuahoe79904c2015-03-18 16:56:42 +0200725 if (mLeft->isArray())
726 {
727 ASSERT(mLeft->getArraySize() == mRight->getArraySize());
728 mType.setArraySize(mLeft->getArraySize());
729 }
Jamie Madillb1a85f42014-08-19 15:23:24 -0400730 }
731 break;
732
733 case EOpEqual:
734 case EOpNotEqual:
735 case EOpLessThan:
736 case EOpGreaterThan:
737 case EOpLessThanEqual:
738 case EOpGreaterThanEqual:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200739 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
740 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400741 setType(TType(EbtBool, EbpUndefined));
742 break;
743
744 default:
745 return false;
746 }
747 return true;
748}
749
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300750TIntermTyped *TIntermBinary::fold(TInfoSink &infoSink)
751{
752 TIntermConstantUnion *leftConstant = mLeft->getAsConstantUnion();
753 TIntermConstantUnion *rightConstant = mRight->getAsConstantUnion();
754 if (leftConstant == nullptr || rightConstant == nullptr)
755 {
756 return nullptr;
757 }
758 TConstantUnion *constArray = leftConstant->foldBinary(mOp, rightConstant, infoSink);
759 if (constArray == nullptr)
760 {
761 return nullptr;
762 }
763 TIntermTyped *folded = new TIntermConstantUnion(constArray, getType());
764 folded->getTypePointer()->setQualifier(EvqConst);
765 folded->setLine(getLine());
766 return folded;
767}
768
Olli Etuaho95310b02015-06-02 17:43:38 +0300769TIntermTyped *TIntermUnary::fold(TInfoSink &infoSink)
770{
771 TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
772 if (operandConstant == nullptr)
773 {
774 return nullptr;
775 }
776 TConstantUnion *constArray = operandConstant->foldUnary(mOp, infoSink);
777 if (constArray == nullptr)
778 {
779 return nullptr;
780 }
781 TIntermTyped *folded = new TIntermConstantUnion(constArray, getType());
782 folded->getTypePointer()->setQualifier(EvqConst);
783 folded->setLine(getLine());
784 return folded;
785}
786
Jamie Madillb1a85f42014-08-19 15:23:24 -0400787//
788// The fold functions see if an operation on a constant can be done in place,
789// without generating run-time code.
790//
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300791// Returns the constant value to keep using or nullptr.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400792//
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300793TConstantUnion *TIntermConstantUnion::foldBinary(TOperator op, TIntermConstantUnion *rightNode, TInfoSink &infoSink)
794{
795 TConstantUnion *leftArray = getUnionArrayPointer();
796 TConstantUnion *rightArray = rightNode->getUnionArrayPointer();
797
798 if (!leftArray)
799 return nullptr;
800 if (!rightArray)
801 return nullptr;
802
803 size_t objectSize = getType().getObjectSize();
804
805 // for a case like float f = vec4(2, 3, 4, 5) + 1.2;
806 if (rightNode->getType().getObjectSize() == 1 && objectSize > 1)
807 {
808 rightArray = Vectorize(*rightNode->getUnionArrayPointer(), objectSize);
809 }
810 else if (rightNode->getType().getObjectSize() > 1 && objectSize == 1)
811 {
812 // for a case like float f = 1.2 + vec4(2, 3, 4, 5);
813 leftArray = Vectorize(*getUnionArrayPointer(), rightNode->getType().getObjectSize());
814 objectSize = rightNode->getType().getObjectSize();
815 }
816
817 TConstantUnion *resultArray = nullptr;
818
819 switch(op)
820 {
821 case EOpAdd:
822 resultArray = new TConstantUnion[objectSize];
823 for (size_t i = 0; i < objectSize; i++)
824 resultArray[i] = leftArray[i] + rightArray[i];
825 break;
826 case EOpSub:
827 resultArray = new TConstantUnion[objectSize];
828 for (size_t i = 0; i < objectSize; i++)
829 resultArray[i] = leftArray[i] - rightArray[i];
830 break;
831
832 case EOpMul:
833 case EOpVectorTimesScalar:
834 case EOpMatrixTimesScalar:
835 resultArray = new TConstantUnion[objectSize];
836 for (size_t i = 0; i < objectSize; i++)
837 resultArray[i] = leftArray[i] * rightArray[i];
838 break;
839
840 case EOpMatrixTimesMatrix:
841 {
842 if (getType().getBasicType() != EbtFloat ||
843 rightNode->getBasicType() != EbtFloat)
844 {
845 infoSink.info.message(
846 EPrefixInternalError, getLine(),
847 "Constant Folding cannot be done for matrix multiply");
848 return nullptr;
849 }
850
851 const int leftCols = getCols();
852 const int leftRows = getRows();
853 const int rightCols = rightNode->getType().getCols();
854 const int rightRows = rightNode->getType().getRows();
855 const int resultCols = rightCols;
856 const int resultRows = leftRows;
857
858 resultArray = new TConstantUnion[resultCols * resultRows];
859 for (int row = 0; row < resultRows; row++)
860 {
861 for (int column = 0; column < resultCols; column++)
862 {
863 resultArray[resultRows * column + row].setFConst(0.0f);
864 for (int i = 0; i < leftCols; i++)
865 {
866 resultArray[resultRows * column + row].setFConst(
867 resultArray[resultRows * column + row].getFConst() +
868 leftArray[i * leftRows + row].getFConst() *
869 rightArray[column * rightRows + i].getFConst());
870 }
871 }
872 }
873 }
874 break;
875
876 case EOpDiv:
877 case EOpIMod:
878 {
879 resultArray = new TConstantUnion[objectSize];
880 for (size_t i = 0; i < objectSize; i++)
881 {
882 switch (getType().getBasicType())
883 {
884 case EbtFloat:
885 if (rightArray[i] == 0.0f)
886 {
887 infoSink.info.message(EPrefixWarning, getLine(),
888 "Divide by zero error during constant folding");
889 resultArray[i].setFConst(leftArray[i].getFConst() < 0 ? -FLT_MAX : FLT_MAX);
890 }
891 else
892 {
893 ASSERT(op == EOpDiv);
894 resultArray[i].setFConst(leftArray[i].getFConst() / rightArray[i].getFConst());
895 }
896 break;
897
898 case EbtInt:
899 if (rightArray[i] == 0)
900 {
901 infoSink.info.message(EPrefixWarning, getLine(),
902 "Divide by zero error during constant folding");
903 resultArray[i].setIConst(INT_MAX);
904 }
905 else
906 {
907 if (op == EOpDiv)
908 {
909 resultArray[i].setIConst(leftArray[i].getIConst() / rightArray[i].getIConst());
910 }
911 else
912 {
913 ASSERT(op == EOpIMod);
914 resultArray[i].setIConst(leftArray[i].getIConst() % rightArray[i].getIConst());
915 }
916 }
917 break;
918
919 case EbtUInt:
920 if (rightArray[i] == 0)
921 {
922 infoSink.info.message(EPrefixWarning, getLine(),
923 "Divide by zero error during constant folding");
924 resultArray[i].setUConst(UINT_MAX);
925 }
926 else
927 {
928 if (op == EOpDiv)
929 {
930 resultArray[i].setUConst(leftArray[i].getUConst() / rightArray[i].getUConst());
931 }
932 else
933 {
934 ASSERT(op == EOpIMod);
935 resultArray[i].setUConst(leftArray[i].getUConst() % rightArray[i].getUConst());
936 }
937 }
938 break;
939
940 default:
941 infoSink.info.message(EPrefixInternalError, getLine(),
942 "Constant folding cannot be done for \"/\"");
943 return nullptr;
944 }
945 }
946 }
947 break;
948
949 case EOpMatrixTimesVector:
950 {
951 if (rightNode->getBasicType() != EbtFloat)
952 {
953 infoSink.info.message(EPrefixInternalError, getLine(),
954 "Constant Folding cannot be done for matrix times vector");
955 return nullptr;
956 }
957
958 const int matrixCols = getCols();
959 const int matrixRows = getRows();
960
961 resultArray = new TConstantUnion[matrixRows];
962
963 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
964 {
965 resultArray[matrixRow].setFConst(0.0f);
966 for (int col = 0; col < matrixCols; col++)
967 {
968 resultArray[matrixRow].setFConst(resultArray[matrixRow].getFConst() +
969 leftArray[col * matrixRows + matrixRow].getFConst() *
970 rightArray[col].getFConst());
971 }
972 }
973 }
974 break;
975
976 case EOpVectorTimesMatrix:
977 {
978 if (getType().getBasicType() != EbtFloat)
979 {
980 infoSink.info.message(EPrefixInternalError, getLine(),
981 "Constant Folding cannot be done for vector times matrix");
982 return nullptr;
983 }
984
985 const int matrixCols = rightNode->getType().getCols();
986 const int matrixRows = rightNode->getType().getRows();
987
988 resultArray = new TConstantUnion[matrixCols];
989
990 for (int matrixCol = 0; matrixCol < matrixCols; matrixCol++)
991 {
992 resultArray[matrixCol].setFConst(0.0f);
993 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
994 {
995 resultArray[matrixCol].setFConst(resultArray[matrixCol].getFConst() +
996 leftArray[matrixRow].getFConst() *
997 rightArray[matrixCol * matrixRows + matrixRow].getFConst());
998 }
999 }
1000 }
1001 break;
1002
1003 case EOpLogicalAnd:
1004 {
1005 resultArray = new TConstantUnion[objectSize];
1006 for (size_t i = 0; i < objectSize; i++)
1007 {
1008 resultArray[i] = leftArray[i] && rightArray[i];
1009 }
1010 }
1011 break;
1012
1013 case EOpLogicalOr:
1014 {
1015 resultArray = new TConstantUnion[objectSize];
1016 for (size_t i = 0; i < objectSize; i++)
1017 {
1018 resultArray[i] = leftArray[i] || rightArray[i];
1019 }
1020 }
1021 break;
1022
1023 case EOpLogicalXor:
1024 {
1025 resultArray = new TConstantUnion[objectSize];
1026 for (size_t i = 0; i < objectSize; i++)
1027 {
1028 switch (getType().getBasicType())
1029 {
1030 case EbtBool:
1031 resultArray[i].setBConst(leftArray[i] != rightArray[i]);
1032 break;
1033 default:
1034 UNREACHABLE();
1035 break;
1036 }
1037 }
1038 }
1039 break;
1040
1041 case EOpBitwiseAnd:
1042 resultArray = new TConstantUnion[objectSize];
1043 for (size_t i = 0; i < objectSize; i++)
1044 resultArray[i] = leftArray[i] & rightArray[i];
1045 break;
1046 case EOpBitwiseXor:
1047 resultArray = new TConstantUnion[objectSize];
1048 for (size_t i = 0; i < objectSize; i++)
1049 resultArray[i] = leftArray[i] ^ rightArray[i];
1050 break;
1051 case EOpBitwiseOr:
1052 resultArray = new TConstantUnion[objectSize];
1053 for (size_t i = 0; i < objectSize; i++)
1054 resultArray[i] = leftArray[i] | rightArray[i];
1055 break;
1056 case EOpBitShiftLeft:
1057 resultArray = new TConstantUnion[objectSize];
1058 for (size_t i = 0; i < objectSize; i++)
1059 resultArray[i] = leftArray[i] << rightArray[i];
1060 break;
1061 case EOpBitShiftRight:
1062 resultArray = new TConstantUnion[objectSize];
1063 for (size_t i = 0; i < objectSize; i++)
1064 resultArray[i] = leftArray[i] >> rightArray[i];
1065 break;
1066
1067 case EOpLessThan:
1068 ASSERT(objectSize == 1);
1069 resultArray = new TConstantUnion[1];
1070 resultArray->setBConst(*leftArray < *rightArray);
1071 break;
1072
1073 case EOpGreaterThan:
1074 ASSERT(objectSize == 1);
1075 resultArray = new TConstantUnion[1];
1076 resultArray->setBConst(*leftArray > *rightArray);
1077 break;
1078
1079 case EOpLessThanEqual:
1080 ASSERT(objectSize == 1);
1081 resultArray = new TConstantUnion[1];
1082 resultArray->setBConst(!(*leftArray > *rightArray));
1083 break;
1084
1085 case EOpGreaterThanEqual:
1086 ASSERT(objectSize == 1);
1087 resultArray = new TConstantUnion[1];
1088 resultArray->setBConst(!(*leftArray < *rightArray));
1089 break;
1090
1091 case EOpEqual:
1092 case EOpNotEqual:
1093 {
1094 resultArray = new TConstantUnion[1];
1095 bool equal = true;
1096 if (getType().getBasicType() == EbtStruct)
1097 {
1098 equal = CompareStructure(getType(), rightArray, leftArray);
1099 }
1100 else
1101 {
1102 for (size_t i = 0; i < objectSize; i++)
1103 {
1104 if (leftArray[i] != rightArray[i])
1105 {
1106 equal = false;
1107 break; // break out of for loop
1108 }
1109 }
1110 }
1111 if (op == EOpEqual)
1112 {
1113 resultArray->setBConst(equal);
1114 }
1115 else
1116 {
1117 resultArray->setBConst(!equal);
1118 }
1119 }
1120 break;
1121
1122 default:
1123 infoSink.info.message(
1124 EPrefixInternalError, getLine(),
1125 "Invalid operator for constant folding");
1126 return nullptr;
1127 }
1128 return resultArray;
1129}
1130
1131//
1132// The fold functions see if an operation on a constant can be done in place,
1133// without generating run-time code.
1134//
Olli Etuaho95310b02015-06-02 17:43:38 +03001135// Returns the constant value to keep using or nullptr.
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001136//
Olli Etuaho95310b02015-06-02 17:43:38 +03001137TConstantUnion *TIntermConstantUnion::foldUnary(TOperator op, TInfoSink &infoSink)
Jamie Madillb1a85f42014-08-19 15:23:24 -04001138{
Olli Etuaho95310b02015-06-02 17:43:38 +03001139 TConstantUnion *operandArray = getUnionArrayPointer();
Jamie Madillb1a85f42014-08-19 15:23:24 -04001140
Olli Etuaho95310b02015-06-02 17:43:38 +03001141 if (!operandArray)
Arun Patolefddc2112015-04-22 13:28:10 +05301142 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001143
1144 size_t objectSize = getType().getObjectSize();
1145
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001146 if (op == EOpAny || op == EOpAll || op == EOpLength)
Arun Patole9d0b1f92015-05-20 14:27:17 +05301147 {
Olli Etuaho95310b02015-06-02 17:43:38 +03001148 // Do operations where the return type has a different number of components compared to the operand type.
1149 TConstantUnion *resultArray = nullptr;
Arun Patole9d0b1f92015-05-20 14:27:17 +05301150
Arun Patole1155ddd2015-06-05 18:04:36 +05301151 switch (op)
Arun Patole9d0b1f92015-05-20 14:27:17 +05301152 {
Arun Patole1155ddd2015-06-05 18:04:36 +05301153 case EOpAny:
Arun Patole9d0b1f92015-05-20 14:27:17 +05301154 if (getType().getBasicType() == EbtBool)
1155 {
Olli Etuaho95310b02015-06-02 17:43:38 +03001156 resultArray = new TConstantUnion();
1157 resultArray->setBConst(false);
Arun Patole9d0b1f92015-05-20 14:27:17 +05301158 for (size_t i = 0; i < objectSize; i++)
1159 {
Olli Etuaho95310b02015-06-02 17:43:38 +03001160 if (operandArray[i].getBConst())
Arun Patole9d0b1f92015-05-20 14:27:17 +05301161 {
Olli Etuaho95310b02015-06-02 17:43:38 +03001162 resultArray->setBConst(true);
Arun Patole9d0b1f92015-05-20 14:27:17 +05301163 break;
1164 }
1165 }
Arun Patole1155ddd2015-06-05 18:04:36 +05301166 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05301167 }
1168 else
1169 {
Arun Patole1155ddd2015-06-05 18:04:36 +05301170 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
Arun Patole9d0b1f92015-05-20 14:27:17 +05301171 return nullptr;
1172 }
Arun Patole1155ddd2015-06-05 18:04:36 +05301173
1174 case EOpAll:
Arun Patole9d0b1f92015-05-20 14:27:17 +05301175 if (getType().getBasicType() == EbtBool)
1176 {
Olli Etuaho95310b02015-06-02 17:43:38 +03001177 resultArray = new TConstantUnion();
1178 resultArray->setBConst(true);
Arun Patole9d0b1f92015-05-20 14:27:17 +05301179 for (size_t i = 0; i < objectSize; i++)
1180 {
Olli Etuaho95310b02015-06-02 17:43:38 +03001181 if (!operandArray[i].getBConst())
Arun Patole9d0b1f92015-05-20 14:27:17 +05301182 {
Olli Etuaho95310b02015-06-02 17:43:38 +03001183 resultArray->setBConst(false);
Arun Patole9d0b1f92015-05-20 14:27:17 +05301184 break;
1185 }
1186 }
Arun Patole1155ddd2015-06-05 18:04:36 +05301187 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05301188 }
1189 else
1190 {
Arun Patole1155ddd2015-06-05 18:04:36 +05301191 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
Arun Patole9d0b1f92015-05-20 14:27:17 +05301192 return nullptr;
1193 }
Arun Patole1155ddd2015-06-05 18:04:36 +05301194
1195 case EOpLength:
1196 if (getType().getBasicType() == EbtFloat)
1197 {
Olli Etuaho95310b02015-06-02 17:43:38 +03001198 resultArray = new TConstantUnion();
1199 resultArray->setFConst(VectorLength(operandArray, objectSize));
Arun Patole1155ddd2015-06-05 18:04:36 +05301200 break;
1201 }
1202 else
1203 {
1204 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1205 return nullptr;
1206 }
1207
1208 default:
1209 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05301210 }
Arun Patole1155ddd2015-06-05 18:04:36 +05301211
Olli Etuaho95310b02015-06-02 17:43:38 +03001212 return resultArray;
Arun Patole9d0b1f92015-05-20 14:27:17 +05301213 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04001214 else
1215 {
1216 //
Arun Patole9d0b1f92015-05-20 14:27:17 +05301217 // Do unary operations where the return type is the same as operand type.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001218 //
Olli Etuaho95310b02015-06-02 17:43:38 +03001219 TConstantUnion *resultArray = new TConstantUnion[objectSize];
Jamie Madillb1a85f42014-08-19 15:23:24 -04001220 for (size_t i = 0; i < objectSize; i++)
1221 {
1222 switch(op)
1223 {
1224 case EOpNegative:
1225 switch (getType().getBasicType())
1226 {
1227 case EbtFloat:
Olli Etuaho95310b02015-06-02 17:43:38 +03001228 resultArray[i].setFConst(-operandArray[i].getFConst());
Jamie Madillb1a85f42014-08-19 15:23:24 -04001229 break;
1230 case EbtInt:
Olli Etuaho95310b02015-06-02 17:43:38 +03001231 resultArray[i].setIConst(-operandArray[i].getIConst());
Jamie Madillb1a85f42014-08-19 15:23:24 -04001232 break;
1233 case EbtUInt:
Olli Etuaho95310b02015-06-02 17:43:38 +03001234 resultArray[i].setUConst(static_cast<unsigned int>(
1235 -static_cast<int>(operandArray[i].getUConst())));
Jamie Madillb1a85f42014-08-19 15:23:24 -04001236 break;
1237 default:
1238 infoSink.info.message(
1239 EPrefixInternalError, getLine(),
1240 "Unary operation not folded into constant");
Arun Patolefddc2112015-04-22 13:28:10 +05301241 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001242 }
1243 break;
1244
Zhenyao Mode1e00e2014-10-09 16:55:32 -07001245 case EOpPositive:
1246 switch (getType().getBasicType())
1247 {
1248 case EbtFloat:
Olli Etuaho95310b02015-06-02 17:43:38 +03001249 resultArray[i].setFConst(operandArray[i].getFConst());
Zhenyao Mode1e00e2014-10-09 16:55:32 -07001250 break;
1251 case EbtInt:
Olli Etuaho95310b02015-06-02 17:43:38 +03001252 resultArray[i].setIConst(operandArray[i].getIConst());
Zhenyao Mode1e00e2014-10-09 16:55:32 -07001253 break;
1254 case EbtUInt:
Olli Etuaho95310b02015-06-02 17:43:38 +03001255 resultArray[i].setUConst(static_cast<unsigned int>(
1256 static_cast<int>(operandArray[i].getUConst())));
Zhenyao Mode1e00e2014-10-09 16:55:32 -07001257 break;
1258 default:
1259 infoSink.info.message(
1260 EPrefixInternalError, getLine(),
1261 "Unary operation not folded into constant");
Arun Patolefddc2112015-04-22 13:28:10 +05301262 return nullptr;
Zhenyao Mode1e00e2014-10-09 16:55:32 -07001263 }
1264 break;
1265
Jamie Madillb1a85f42014-08-19 15:23:24 -04001266 case EOpLogicalNot:
1267 // this code is written for possible future use,
1268 // will not get executed currently
1269 switch (getType().getBasicType())
1270 {
1271 case EbtBool:
Olli Etuaho95310b02015-06-02 17:43:38 +03001272 resultArray[i].setBConst(!operandArray[i].getBConst());
Jamie Madillb1a85f42014-08-19 15:23:24 -04001273 break;
1274 default:
1275 infoSink.info.message(
1276 EPrefixInternalError, getLine(),
1277 "Unary operation not folded into constant");
Arun Patolefddc2112015-04-22 13:28:10 +05301278 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001279 }
1280 break;
1281
Olli Etuaho31b5fc62015-01-16 12:13:36 +02001282 case EOpBitwiseNot:
1283 switch (getType().getBasicType())
1284 {
1285 case EbtInt:
Olli Etuaho95310b02015-06-02 17:43:38 +03001286 resultArray[i].setIConst(~operandArray[i].getIConst());
Olli Etuaho31b5fc62015-01-16 12:13:36 +02001287 break;
1288 case EbtUInt:
Olli Etuaho95310b02015-06-02 17:43:38 +03001289 resultArray[i].setUConst(~operandArray[i].getUConst());
Olli Etuaho31b5fc62015-01-16 12:13:36 +02001290 break;
1291 default:
1292 infoSink.info.message(
1293 EPrefixInternalError, getLine(),
1294 "Unary operation not folded into constant");
Arun Patolefddc2112015-04-22 13:28:10 +05301295 return nullptr;
Olli Etuaho31b5fc62015-01-16 12:13:36 +02001296 }
1297 break;
1298
Arun Patole9dea48f2015-04-02 11:45:09 +05301299 case EOpRadians:
1300 if (getType().getBasicType() == EbtFloat)
1301 {
Olli Etuaho95310b02015-06-02 17:43:38 +03001302 resultArray[i].setFConst(kDegreesToRadiansMultiplier * operandArray[i].getFConst());
Arun Patole9dea48f2015-04-02 11:45:09 +05301303 break;
1304 }
1305 infoSink.info.message(
1306 EPrefixInternalError, getLine(),
1307 "Unary operation not folded into constant");
1308 return nullptr;
1309
1310 case EOpDegrees:
1311 if (getType().getBasicType() == EbtFloat)
1312 {
Olli Etuaho95310b02015-06-02 17:43:38 +03001313 resultArray[i].setFConst(kRadiansToDegreesMultiplier * operandArray[i].getFConst());
Arun Patole9dea48f2015-04-02 11:45:09 +05301314 break;
1315 }
1316 infoSink.info.message(
1317 EPrefixInternalError, getLine(),
1318 "Unary operation not folded into constant");
1319 return nullptr;
1320
1321 case EOpSin:
Olli Etuaho95310b02015-06-02 17:43:38 +03001322 if (!foldFloatTypeUnary(operandArray[i], &sinf, infoSink, &resultArray[i]))
Arun Patole9dea48f2015-04-02 11:45:09 +05301323 return nullptr;
1324 break;
1325
1326 case EOpCos:
Olli Etuaho95310b02015-06-02 17:43:38 +03001327 if (!foldFloatTypeUnary(operandArray[i], &cosf, infoSink, &resultArray[i]))
Arun Patole9dea48f2015-04-02 11:45:09 +05301328 return nullptr;
1329 break;
1330
1331 case EOpTan:
Olli Etuaho95310b02015-06-02 17:43:38 +03001332 if (!foldFloatTypeUnary(operandArray[i], &tanf, infoSink, &resultArray[i]))
Arun Patole9dea48f2015-04-02 11:45:09 +05301333 return nullptr;
1334 break;
1335
1336 case EOpAsin:
1337 // For asin(x), results are undefined if |x| > 1, we are choosing to set result to 0.
Olli Etuaho95310b02015-06-02 17:43:38 +03001338 if (getType().getBasicType() == EbtFloat && fabsf(operandArray[i].getFConst()) > 1.0f)
1339 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1340 else if (!foldFloatTypeUnary(operandArray[i], &asinf, infoSink, &resultArray[i]))
Arun Patole9dea48f2015-04-02 11:45:09 +05301341 return nullptr;
1342 break;
1343
1344 case EOpAcos:
1345 // For acos(x), results are undefined if |x| > 1, we are choosing to set result to 0.
Olli Etuaho95310b02015-06-02 17:43:38 +03001346 if (getType().getBasicType() == EbtFloat && fabsf(operandArray[i].getFConst()) > 1.0f)
1347 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1348 else if (!foldFloatTypeUnary(operandArray[i], &acosf, infoSink, &resultArray[i]))
Arun Patole9dea48f2015-04-02 11:45:09 +05301349 return nullptr;
1350 break;
1351
1352 case EOpAtan:
Olli Etuaho95310b02015-06-02 17:43:38 +03001353 if (!foldFloatTypeUnary(operandArray[i], &atanf, infoSink, &resultArray[i]))
Arun Patole9dea48f2015-04-02 11:45:09 +05301354 return nullptr;
1355 break;
1356
1357 case EOpSinh:
Olli Etuaho95310b02015-06-02 17:43:38 +03001358 if (!foldFloatTypeUnary(operandArray[i], &sinhf, infoSink, &resultArray[i]))
Arun Patole9dea48f2015-04-02 11:45:09 +05301359 return nullptr;
1360 break;
1361
1362 case EOpCosh:
Olli Etuaho95310b02015-06-02 17:43:38 +03001363 if (!foldFloatTypeUnary(operandArray[i], &coshf, infoSink, &resultArray[i]))
Arun Patole9dea48f2015-04-02 11:45:09 +05301364 return nullptr;
1365 break;
1366
1367 case EOpTanh:
Olli Etuaho95310b02015-06-02 17:43:38 +03001368 if (!foldFloatTypeUnary(operandArray[i], &tanhf, infoSink, &resultArray[i]))
Arun Patole9dea48f2015-04-02 11:45:09 +05301369 return nullptr;
1370 break;
1371
1372 case EOpAsinh:
Olli Etuaho95310b02015-06-02 17:43:38 +03001373 if (!foldFloatTypeUnary(operandArray[i], &asinhf, infoSink, &resultArray[i]))
Arun Patole9dea48f2015-04-02 11:45:09 +05301374 return nullptr;
1375 break;
1376
1377 case EOpAcosh:
1378 // For acosh(x), results are undefined if x < 1, we are choosing to set result to 0.
Olli Etuaho95310b02015-06-02 17:43:38 +03001379 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() < 1.0f)
1380 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1381 else if (!foldFloatTypeUnary(operandArray[i], &acoshf, infoSink, &resultArray[i]))
Arun Patole9dea48f2015-04-02 11:45:09 +05301382 return nullptr;
1383 break;
1384
1385 case EOpAtanh:
1386 // For atanh(x), results are undefined if |x| >= 1, we are choosing to set result to 0.
Olli Etuaho95310b02015-06-02 17:43:38 +03001387 if (getType().getBasicType() == EbtFloat && fabsf(operandArray[i].getFConst()) >= 1.0f)
1388 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1389 else if (!foldFloatTypeUnary(operandArray[i], &atanhf, infoSink, &resultArray[i]))
Arun Patole9dea48f2015-04-02 11:45:09 +05301390 return nullptr;
1391 break;
1392
Arun Patole97dc22e2015-04-06 17:35:38 +05301393 case EOpAbs:
1394 switch (getType().getBasicType())
1395 {
1396 case EbtFloat:
Olli Etuaho95310b02015-06-02 17:43:38 +03001397 resultArray[i].setFConst(fabsf(operandArray[i].getFConst()));
Arun Patole97dc22e2015-04-06 17:35:38 +05301398 break;
1399 case EbtInt:
Olli Etuaho95310b02015-06-02 17:43:38 +03001400 resultArray[i].setIConst(abs(operandArray[i].getIConst()));
Arun Patole97dc22e2015-04-06 17:35:38 +05301401 break;
1402 default:
1403 infoSink.info.message(
1404 EPrefixInternalError, getLine(),
1405 "Unary operation not folded into constant");
1406 return nullptr;
1407 }
1408 break;
1409
1410 case EOpSign:
1411 switch (getType().getBasicType())
1412 {
1413 case EbtFloat:
1414 {
Olli Etuaho95310b02015-06-02 17:43:38 +03001415 float fConst = operandArray[i].getFConst();
Arun Patole97dc22e2015-04-06 17:35:38 +05301416 float fResult = 0.0f;
1417 if (fConst > 0.0f)
1418 fResult = 1.0f;
1419 else if (fConst < 0.0f)
1420 fResult = -1.0f;
Olli Etuaho95310b02015-06-02 17:43:38 +03001421 resultArray[i].setFConst(fResult);
Arun Patole97dc22e2015-04-06 17:35:38 +05301422 }
1423 break;
1424 case EbtInt:
1425 {
Olli Etuaho95310b02015-06-02 17:43:38 +03001426 int iConst = operandArray[i].getIConst();
Arun Patole97dc22e2015-04-06 17:35:38 +05301427 int iResult = 0;
1428 if (iConst > 0)
1429 iResult = 1;
1430 else if (iConst < 0)
1431 iResult = -1;
Olli Etuaho95310b02015-06-02 17:43:38 +03001432 resultArray[i].setIConst(iResult);
Arun Patole97dc22e2015-04-06 17:35:38 +05301433 }
1434 break;
1435 default:
1436 infoSink.info.message(
1437 EPrefixInternalError, getLine(),
1438 "Unary operation not folded into constant");
1439 return nullptr;
1440 }
1441 break;
1442
1443 case EOpFloor:
Olli Etuaho95310b02015-06-02 17:43:38 +03001444 if (!foldFloatTypeUnary(operandArray[i], &floorf, infoSink, &resultArray[i]))
Arun Patole97dc22e2015-04-06 17:35:38 +05301445 return nullptr;
1446 break;
1447
1448 case EOpTrunc:
Olli Etuaho95310b02015-06-02 17:43:38 +03001449 if (!foldFloatTypeUnary(operandArray[i], &truncf, infoSink, &resultArray[i]))
Arun Patole97dc22e2015-04-06 17:35:38 +05301450 return nullptr;
1451 break;
1452
1453 case EOpRound:
Olli Etuaho95310b02015-06-02 17:43:38 +03001454 if (!foldFloatTypeUnary(operandArray[i], &roundf, infoSink, &resultArray[i]))
Arun Patole97dc22e2015-04-06 17:35:38 +05301455 return nullptr;
1456 break;
1457
1458 case EOpRoundEven:
1459 if (getType().getBasicType() == EbtFloat)
1460 {
Olli Etuaho95310b02015-06-02 17:43:38 +03001461 float x = operandArray[i].getFConst();
Arun Patole97dc22e2015-04-06 17:35:38 +05301462 float result;
1463 float fractPart = modff(x, &result);
1464 if (fabsf(fractPart) == 0.5f)
1465 result = 2.0f * roundf(x / 2.0f);
1466 else
1467 result = roundf(x);
Olli Etuaho95310b02015-06-02 17:43:38 +03001468 resultArray[i].setFConst(result);
Arun Patole97dc22e2015-04-06 17:35:38 +05301469 break;
1470 }
1471 infoSink.info.message(
1472 EPrefixInternalError, getLine(),
1473 "Unary operation not folded into constant");
1474 return nullptr;
1475
1476 case EOpCeil:
Olli Etuaho95310b02015-06-02 17:43:38 +03001477 if (!foldFloatTypeUnary(operandArray[i], &ceilf, infoSink, &resultArray[i]))
Arun Patole97dc22e2015-04-06 17:35:38 +05301478 return nullptr;
1479 break;
1480
1481 case EOpFract:
1482 if (getType().getBasicType() == EbtFloat)
1483 {
Olli Etuaho95310b02015-06-02 17:43:38 +03001484 float x = operandArray[i].getFConst();
1485 resultArray[i].setFConst(x - floorf(x));
Arun Patole97dc22e2015-04-06 17:35:38 +05301486 break;
1487 }
1488 infoSink.info.message(
1489 EPrefixInternalError, getLine(),
1490 "Unary operation not folded into constant");
1491 return nullptr;
1492
Arun Patole28eb65e2015-04-06 17:29:48 +05301493 case EOpExp:
Olli Etuaho95310b02015-06-02 17:43:38 +03001494 if (!foldFloatTypeUnary(operandArray[i], &expf, infoSink, &resultArray[i]))
Arun Patole28eb65e2015-04-06 17:29:48 +05301495 return nullptr;
1496 break;
1497
1498 case EOpLog:
1499 // For log(x), results are undefined if x <= 0, we are choosing to set result to 0.
Olli Etuaho95310b02015-06-02 17:43:38 +03001500 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() <= 0.0f)
1501 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1502 else if (!foldFloatTypeUnary(operandArray[i], &logf, infoSink, &resultArray[i]))
Arun Patole28eb65e2015-04-06 17:29:48 +05301503 return nullptr;
1504 break;
1505
1506 case EOpExp2:
Olli Etuaho95310b02015-06-02 17:43:38 +03001507 if (!foldFloatTypeUnary(operandArray[i], &exp2f, infoSink, &resultArray[i]))
Arun Patole28eb65e2015-04-06 17:29:48 +05301508 return nullptr;
1509 break;
1510
1511 case EOpLog2:
1512 // For log2(x), results are undefined if x <= 0, we are choosing to set result to 0.
1513 // 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 +03001514 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() <= 0.0f)
1515 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1516 else if (!foldFloatTypeUnary(operandArray[i], &logf, infoSink, &resultArray[i]))
Arun Patole28eb65e2015-04-06 17:29:48 +05301517 return nullptr;
1518 else
Olli Etuaho95310b02015-06-02 17:43:38 +03001519 resultArray[i].setFConst(resultArray[i].getFConst() / logf(2.0f));
Arun Patole28eb65e2015-04-06 17:29:48 +05301520 break;
1521
1522 case EOpSqrt:
1523 // For sqrt(x), results are undefined if x < 0, we are choosing to set result to 0.
Olli Etuaho95310b02015-06-02 17:43:38 +03001524 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() < 0.0f)
1525 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1526 else if (!foldFloatTypeUnary(operandArray[i], &sqrtf, infoSink, &resultArray[i]))
Arun Patole28eb65e2015-04-06 17:29:48 +05301527 return nullptr;
1528 break;
1529
1530 case EOpInverseSqrt:
1531 // There is no stdlib built-in function equavalent for GLES built-in inversesqrt(),
1532 // so getting the square root first using builtin function sqrt() and then taking its inverse.
1533 // 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 +03001534 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() <= 0.0f)
1535 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1536 else if (!foldFloatTypeUnary(operandArray[i], &sqrtf, infoSink, &resultArray[i]))
Arun Patole28eb65e2015-04-06 17:29:48 +05301537 return nullptr;
1538 else
Olli Etuaho95310b02015-06-02 17:43:38 +03001539 resultArray[i].setFConst(1.0f / resultArray[i].getFConst());
Arun Patole28eb65e2015-04-06 17:29:48 +05301540 break;
1541
Arun Patole9d0b1f92015-05-20 14:27:17 +05301542 case EOpVectorLogicalNot:
1543 if (getType().getBasicType() == EbtBool)
1544 {
Olli Etuaho95310b02015-06-02 17:43:38 +03001545 resultArray[i].setBConst(!operandArray[i].getBConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05301546 break;
1547 }
1548 infoSink.info.message(
1549 EPrefixInternalError, getLine(),
1550 "Unary operation not folded into constant");
1551 return nullptr;
1552
Arun Patole1155ddd2015-06-05 18:04:36 +05301553 case EOpNormalize:
1554 if (getType().getBasicType() == EbtFloat)
1555 {
Olli Etuaho95310b02015-06-02 17:43:38 +03001556 float x = operandArray[i].getFConst();
1557 float length = VectorLength(operandArray, objectSize);
Arun Patole1155ddd2015-06-05 18:04:36 +05301558 if (length)
Olli Etuaho95310b02015-06-02 17:43:38 +03001559 resultArray[i].setFConst(x / length);
Arun Patole1155ddd2015-06-05 18:04:36 +05301560 else
Olli Etuaho95310b02015-06-02 17:43:38 +03001561 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink,
1562 &resultArray[i]);
Arun Patole1155ddd2015-06-05 18:04:36 +05301563 break;
1564 }
1565 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1566 return nullptr;
1567
Jamie Madillb1a85f42014-08-19 15:23:24 -04001568 default:
Arun Patolefddc2112015-04-22 13:28:10 +05301569 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001570 }
1571 }
Olli Etuaho95310b02015-06-02 17:43:38 +03001572 return resultArray;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001573 }
1574}
1575
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001576bool TIntermConstantUnion::foldFloatTypeUnary(const TConstantUnion &parameter, FloatTypeUnaryFunc builtinFunc,
1577 TInfoSink &infoSink, TConstantUnion *result) const
Arun Patole9dea48f2015-04-02 11:45:09 +05301578{
1579 ASSERT(builtinFunc);
1580
1581 if (getType().getBasicType() == EbtFloat)
1582 {
1583 result->setFConst(builtinFunc(parameter.getFConst()));
1584 return true;
1585 }
1586
1587 infoSink.info.message(
1588 EPrefixInternalError, getLine(),
1589 "Unary operation not folded into constant");
1590 return false;
1591}
1592
Jamie Madillb1a85f42014-08-19 15:23:24 -04001593// static
Arun Patolebf790422015-05-18 17:53:04 +05301594TIntermTyped *TIntermConstantUnion::FoldAggregateBuiltIn(TOperator op, TIntermAggregate *aggregate, TInfoSink &infoSink)
Arun Patole274f0702015-05-05 13:33:30 +05301595{
1596 TIntermSequence *sequence = aggregate->getSequence();
1597 unsigned int paramsCount = sequence->size();
1598 std::vector<TConstantUnion *> unionArrays(paramsCount);
1599 std::vector<size_t> objectSizes(paramsCount);
1600 TType *maxSizeType = nullptr;
1601 TBasicType basicType = EbtVoid;
1602 TSourceLoc loc;
1603 for (unsigned int i = 0; i < paramsCount; i++)
1604 {
1605 TIntermConstantUnion *paramConstant = (*sequence)[i]->getAsConstantUnion();
1606 // Make sure that all params are constant before actual constant folding.
1607 if (!paramConstant)
1608 return nullptr;
1609
1610 if (i == 0)
1611 {
1612 basicType = paramConstant->getType().getBasicType();
1613 loc = paramConstant->getLine();
1614 }
1615 unionArrays[i] = paramConstant->getUnionArrayPointer();
1616 objectSizes[i] = paramConstant->getType().getObjectSize();
1617 if (maxSizeType == nullptr || (objectSizes[i] >= maxSizeType->getObjectSize()))
1618 maxSizeType = paramConstant->getTypePointer();
1619 }
1620
1621 size_t maxObjectSize = maxSizeType->getObjectSize();
1622 for (unsigned int i = 0; i < paramsCount; i++)
1623 if (objectSizes[i] != maxObjectSize)
1624 unionArrays[i] = Vectorize(*unionArrays[i], maxObjectSize);
1625
1626 TConstantUnion *tempConstArray = nullptr;
1627 TIntermConstantUnion *tempNode = nullptr;
1628 TType returnType = *maxSizeType;
1629 if (paramsCount == 2)
1630 {
1631 //
1632 // Binary built-in
1633 //
1634 switch (op)
1635 {
Arun Patolebf790422015-05-18 17:53:04 +05301636 case EOpAtan:
1637 {
1638 if (basicType == EbtFloat)
1639 {
1640 tempConstArray = new TConstantUnion[maxObjectSize];
1641 for (size_t i = 0; i < maxObjectSize; i++)
1642 {
1643 float y = unionArrays[0][i].getFConst();
1644 float x = unionArrays[1][i].getFConst();
1645 // Results are undefined if x and y are both 0.
1646 if (x == 0.0f && y == 0.0f)
1647 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &tempConstArray[i]);
1648 else
1649 tempConstArray[i].setFConst(atan2f(y, x));
1650 }
1651 }
1652 else
1653 UNREACHABLE();
1654 }
1655 break;
1656
1657 case EOpPow:
1658 {
1659 if (basicType == EbtFloat)
1660 {
1661 tempConstArray = new TConstantUnion[maxObjectSize];
1662 for (size_t i = 0; i < maxObjectSize; i++)
1663 {
1664 float x = unionArrays[0][i].getFConst();
1665 float y = unionArrays[1][i].getFConst();
1666 // Results are undefined if x < 0.
1667 // Results are undefined if x = 0 and y <= 0.
1668 if (x < 0.0f)
1669 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &tempConstArray[i]);
1670 else if (x == 0.0f && y <= 0.0f)
1671 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &tempConstArray[i]);
1672 else
1673 tempConstArray[i].setFConst(powf(x, y));
1674 }
1675 }
1676 else
1677 UNREACHABLE();
1678 }
1679 break;
1680
1681 case EOpMod:
1682 {
1683 if (basicType == EbtFloat)
1684 {
1685 tempConstArray = new TConstantUnion[maxObjectSize];
1686 for (size_t i = 0; i < maxObjectSize; i++)
1687 {
1688 float x = unionArrays[0][i].getFConst();
1689 float y = unionArrays[1][i].getFConst();
1690 tempConstArray[i].setFConst(x - y * floorf(x / y));
1691 }
1692 }
1693 else
1694 UNREACHABLE();
1695 }
1696 break;
1697
Arun Patole274f0702015-05-05 13:33:30 +05301698 case EOpMin:
1699 {
1700 tempConstArray = new TConstantUnion[maxObjectSize];
1701 for (size_t i = 0; i < maxObjectSize; i++)
1702 {
1703 switch (basicType)
1704 {
1705 case EbtFloat:
1706 tempConstArray[i].setFConst(std::min(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
1707 break;
1708 case EbtInt:
1709 tempConstArray[i].setIConst(std::min(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
1710 break;
1711 case EbtUInt:
1712 tempConstArray[i].setUConst(std::min(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
1713 break;
1714 default:
1715 UNREACHABLE();
1716 break;
1717 }
1718 }
1719 }
1720 break;
1721
1722 case EOpMax:
1723 {
1724 tempConstArray = new TConstantUnion[maxObjectSize];
1725 for (size_t i = 0; i < maxObjectSize; i++)
1726 {
1727 switch (basicType)
1728 {
1729 case EbtFloat:
1730 tempConstArray[i].setFConst(std::max(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
1731 break;
1732 case EbtInt:
1733 tempConstArray[i].setIConst(std::max(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
1734 break;
1735 case EbtUInt:
1736 tempConstArray[i].setUConst(std::max(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
1737 break;
1738 default:
1739 UNREACHABLE();
1740 break;
1741 }
1742 }
1743 }
1744 break;
1745
Arun Patolebf790422015-05-18 17:53:04 +05301746 case EOpStep:
1747 {
1748 if (basicType == EbtFloat)
1749 {
1750 tempConstArray = new TConstantUnion[maxObjectSize];
1751 for (size_t i = 0; i < maxObjectSize; i++)
1752 tempConstArray[i].setFConst(unionArrays[1][i].getFConst() < unionArrays[0][i].getFConst() ? 0.0f : 1.0f);
1753 }
1754 else
1755 UNREACHABLE();
1756 }
1757 break;
1758
Arun Patole9d0b1f92015-05-20 14:27:17 +05301759 case EOpLessThan:
1760 {
1761 tempConstArray = new TConstantUnion[maxObjectSize];
1762 for (size_t i = 0; i < maxObjectSize; i++)
1763 {
1764 switch (basicType)
1765 {
1766 case EbtFloat:
1767 tempConstArray[i].setBConst(unionArrays[0][i].getFConst() < unionArrays[1][i].getFConst());
1768 break;
1769 case EbtInt:
1770 tempConstArray[i].setBConst(unionArrays[0][i].getIConst() < unionArrays[1][i].getIConst());
1771 break;
1772 case EbtUInt:
1773 tempConstArray[i].setBConst(unionArrays[0][i].getUConst() < unionArrays[1][i].getUConst());
1774 break;
1775 default:
1776 UNREACHABLE();
1777 break;
1778 }
1779 }
1780 }
1781 break;
1782
1783 case EOpLessThanEqual:
1784 {
1785 tempConstArray = new TConstantUnion[maxObjectSize];
1786 for (size_t i = 0; i < maxObjectSize; i++)
1787 {
1788 switch (basicType)
1789 {
1790 case EbtFloat:
1791 tempConstArray[i].setBConst(unionArrays[0][i].getFConst() <= unionArrays[1][i].getFConst());
1792 break;
1793 case EbtInt:
1794 tempConstArray[i].setBConst(unionArrays[0][i].getIConst() <= unionArrays[1][i].getIConst());
1795 break;
1796 case EbtUInt:
1797 tempConstArray[i].setBConst(unionArrays[0][i].getUConst() <= unionArrays[1][i].getUConst());
1798 break;
1799 default:
1800 UNREACHABLE();
1801 break;
1802 }
1803 }
1804 }
1805 break;
1806
1807 case EOpGreaterThan:
1808 {
1809 tempConstArray = new TConstantUnion[maxObjectSize];
1810 for (size_t i = 0; i < maxObjectSize; i++)
1811 {
1812 switch (basicType)
1813 {
1814 case EbtFloat:
1815 tempConstArray[i].setBConst(unionArrays[0][i].getFConst() > unionArrays[1][i].getFConst());
1816 break;
1817 case EbtInt:
1818 tempConstArray[i].setBConst(unionArrays[0][i].getIConst() > unionArrays[1][i].getIConst());
1819 break;
1820 case EbtUInt:
1821 tempConstArray[i].setBConst(unionArrays[0][i].getUConst() > unionArrays[1][i].getUConst());
1822 break;
1823 default:
1824 UNREACHABLE();
1825 break;
1826 }
1827 }
1828 }
1829 break;
1830
1831 case EOpGreaterThanEqual:
1832 {
1833 tempConstArray = new TConstantUnion[maxObjectSize];
1834 for (size_t i = 0; i < maxObjectSize; i++)
1835 {
1836 switch (basicType)
1837 {
1838 case EbtFloat:
1839 tempConstArray[i].setBConst(unionArrays[0][i].getFConst() >= unionArrays[1][i].getFConst());
1840 break;
1841 case EbtInt:
1842 tempConstArray[i].setBConst(unionArrays[0][i].getIConst() >= unionArrays[1][i].getIConst());
1843 break;
1844 case EbtUInt:
1845 tempConstArray[i].setBConst(unionArrays[0][i].getUConst() >= unionArrays[1][i].getUConst());
1846 break;
1847 default:
1848 UNREACHABLE();
1849 break;
1850 }
1851 }
1852 }
1853 break;
1854
1855 case EOpVectorEqual:
1856 {
1857 tempConstArray = new TConstantUnion[maxObjectSize];
1858 for (size_t i = 0; i < maxObjectSize; i++)
1859 {
1860 switch (basicType)
1861 {
1862 case EbtFloat:
1863 tempConstArray[i].setBConst(unionArrays[0][i].getFConst() == unionArrays[1][i].getFConst());
1864 break;
1865 case EbtInt:
1866 tempConstArray[i].setBConst(unionArrays[0][i].getIConst() == unionArrays[1][i].getIConst());
1867 break;
1868 case EbtUInt:
1869 tempConstArray[i].setBConst(unionArrays[0][i].getUConst() == unionArrays[1][i].getUConst());
1870 break;
1871 case EbtBool:
1872 tempConstArray[i].setBConst(unionArrays[0][i].getBConst() == unionArrays[1][i].getBConst());
1873 break;
1874 default:
1875 UNREACHABLE();
1876 break;
1877 }
1878 }
1879 }
1880 break;
1881
1882 case EOpVectorNotEqual:
1883 {
1884 tempConstArray = new TConstantUnion[maxObjectSize];
1885 for (size_t i = 0; i < maxObjectSize; i++)
1886 {
1887 switch (basicType)
1888 {
1889 case EbtFloat:
1890 tempConstArray[i].setBConst(unionArrays[0][i].getFConst() != unionArrays[1][i].getFConst());
1891 break;
1892 case EbtInt:
1893 tempConstArray[i].setBConst(unionArrays[0][i].getIConst() != unionArrays[1][i].getIConst());
1894 break;
1895 case EbtUInt:
1896 tempConstArray[i].setBConst(unionArrays[0][i].getUConst() != unionArrays[1][i].getUConst());
1897 break;
1898 case EbtBool:
1899 tempConstArray[i].setBConst(unionArrays[0][i].getBConst() != unionArrays[1][i].getBConst());
1900 break;
1901 default:
1902 UNREACHABLE();
1903 break;
1904 }
1905 }
1906 }
1907 break;
1908
Arun Patole1155ddd2015-06-05 18:04:36 +05301909 case EOpDistance:
1910 if (basicType == EbtFloat)
1911 {
1912 TConstantUnion *distanceArray = new TConstantUnion[maxObjectSize];
1913 tempConstArray = new TConstantUnion();
1914 for (size_t i = 0; i < maxObjectSize; i++)
1915 {
1916 float x = unionArrays[0][i].getFConst();
1917 float y = unionArrays[1][i].getFConst();
1918 distanceArray[i].setFConst(x - y);
1919 }
1920 tempConstArray->setFConst(VectorLength(distanceArray, maxObjectSize));
1921 }
1922 else
1923 UNREACHABLE();
1924 break;
1925
1926 case EOpDot:
1927 if (basicType == EbtFloat)
1928 {
1929 tempConstArray = new TConstantUnion();
1930 tempConstArray->setFConst(VectorDotProduct(unionArrays[0], unionArrays[1], maxObjectSize));
1931 }
1932 else
1933 UNREACHABLE();
1934 break;
1935
1936 case EOpCross:
1937 if (basicType == EbtFloat && maxObjectSize == 3)
1938 {
1939 tempConstArray = new TConstantUnion[maxObjectSize];
1940 float x0 = unionArrays[0][0].getFConst();
1941 float x1 = unionArrays[0][1].getFConst();
1942 float x2 = unionArrays[0][2].getFConst();
1943 float y0 = unionArrays[1][0].getFConst();
1944 float y1 = unionArrays[1][1].getFConst();
1945 float y2 = unionArrays[1][2].getFConst();
1946 tempConstArray[0].setFConst(x1 * y2 - y1 * x2);
1947 tempConstArray[1].setFConst(x2 * y0 - y2 * x0);
1948 tempConstArray[2].setFConst(x0 * y1 - y0 * x1);
1949 }
1950 else
1951 UNREACHABLE();
1952 break;
1953
1954 case EOpReflect:
1955 if (basicType == EbtFloat)
1956 {
1957 // genType reflect (genType I, genType N) :
1958 // For the incident vector I and surface orientation N, returns the reflection direction:
1959 // I - 2 * dot(N, I) * N.
1960 tempConstArray = new TConstantUnion[maxObjectSize];
1961 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
1962 for (size_t i = 0; i < maxObjectSize; i++)
1963 {
1964 float result = unionArrays[0][i].getFConst() -
1965 2.0f * dotProduct * unionArrays[1][i].getFConst();
1966 tempConstArray[i].setFConst(result);
1967 }
1968 }
1969 else
1970 UNREACHABLE();
1971 break;
1972
Arun Patole274f0702015-05-05 13:33:30 +05301973 default:
1974 UNREACHABLE();
1975 // TODO: Add constant folding support for other built-in operations that take 2 parameters and not handled above.
1976 return nullptr;
1977 }
1978 }
1979 else if (paramsCount == 3)
1980 {
1981 //
1982 // Ternary built-in
1983 //
1984 switch (op)
1985 {
1986 case EOpClamp:
1987 {
1988 tempConstArray = new TConstantUnion[maxObjectSize];
1989 for (size_t i = 0; i < maxObjectSize; i++)
1990 {
1991 switch (basicType)
1992 {
1993 case EbtFloat:
1994 {
1995 float x = unionArrays[0][i].getFConst();
1996 float min = unionArrays[1][i].getFConst();
1997 float max = unionArrays[2][i].getFConst();
1998 // Results are undefined if min > max.
1999 if (min > max)
Arun Patole081c3f22015-05-25 15:43:35 +05302000 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &tempConstArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302001 else
2002 tempConstArray[i].setFConst(gl::clamp(x, min, max));
2003 }
2004 break;
2005 case EbtInt:
2006 {
2007 int x = unionArrays[0][i].getIConst();
2008 int min = unionArrays[1][i].getIConst();
2009 int max = unionArrays[2][i].getIConst();
2010 // Results are undefined if min > max.
2011 if (min > max)
Arun Patole081c3f22015-05-25 15:43:35 +05302012 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &tempConstArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302013 else
2014 tempConstArray[i].setIConst(gl::clamp(x, min, max));
2015 }
2016 break;
2017 case EbtUInt:
2018 {
2019 unsigned int x = unionArrays[0][i].getUConst();
2020 unsigned int min = unionArrays[1][i].getUConst();
2021 unsigned int max = unionArrays[2][i].getUConst();
2022 // Results are undefined if min > max.
2023 if (min > max)
Arun Patole081c3f22015-05-25 15:43:35 +05302024 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &tempConstArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302025 else
2026 tempConstArray[i].setUConst(gl::clamp(x, min, max));
2027 }
2028 break;
2029 default:
2030 UNREACHABLE();
2031 break;
2032 }
2033 }
2034 }
2035 break;
2036
Arun Patolebf790422015-05-18 17:53:04 +05302037 case EOpMix:
2038 {
2039 if (basicType == EbtFloat)
2040 {
2041 tempConstArray = new TConstantUnion[maxObjectSize];
2042 for (size_t i = 0; i < maxObjectSize; i++)
2043 {
2044 float x = unionArrays[0][i].getFConst();
2045 float y = unionArrays[1][i].getFConst();
2046 TBasicType type = (*sequence)[2]->getAsTyped()->getType().getBasicType();
2047 if (type == EbtFloat)
2048 {
2049 // Returns the linear blend of x and y, i.e., x * (1 - a) + y * a.
2050 float a = unionArrays[2][i].getFConst();
2051 tempConstArray[i].setFConst(x * (1.0f - a) + y * a);
2052 }
2053 else // 3rd parameter is EbtBool
2054 {
2055 ASSERT(type == EbtBool);
2056 // Selects which vector each returned component comes from.
2057 // For a component of a that is false, the corresponding component of x is returned.
2058 // For a component of a that is true, the corresponding component of y is returned.
2059 bool a = unionArrays[2][i].getBConst();
2060 tempConstArray[i].setFConst(a ? y : x);
2061 }
2062 }
2063 }
2064 else
2065 UNREACHABLE();
2066 }
2067 break;
2068
2069 case EOpSmoothStep:
2070 {
2071 if (basicType == EbtFloat)
2072 {
2073 tempConstArray = new TConstantUnion[maxObjectSize];
2074 for (size_t i = 0; i < maxObjectSize; i++)
2075 {
2076 float edge0 = unionArrays[0][i].getFConst();
2077 float edge1 = unionArrays[1][i].getFConst();
2078 float x = unionArrays[2][i].getFConst();
2079 // Results are undefined if edge0 >= edge1.
2080 if (edge0 >= edge1)
2081 {
2082 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &tempConstArray[i]);
2083 }
2084 else
2085 {
2086 // Returns 0.0 if x <= edge0 and 1.0 if x >= edge1 and performs smooth
2087 // Hermite interpolation between 0 and 1 when edge0 < x < edge1.
2088 float t = gl::clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f);
2089 tempConstArray[i].setFConst(t * t * (3.0f - 2.0f * t));
2090 }
2091 }
2092 }
2093 else
2094 UNREACHABLE();
2095 }
2096 break;
2097
Arun Patole1155ddd2015-06-05 18:04:36 +05302098 case EOpFaceForward:
2099 if (basicType == EbtFloat)
2100 {
2101 // genType faceforward(genType N, genType I, genType Nref) :
2102 // If dot(Nref, I) < 0 return N, otherwise return -N.
2103 tempConstArray = new TConstantUnion[maxObjectSize];
2104 float dotProduct = VectorDotProduct(unionArrays[2], unionArrays[1], maxObjectSize);
2105 for (size_t i = 0; i < maxObjectSize; i++)
2106 {
2107 if (dotProduct < 0)
2108 tempConstArray[i].setFConst(unionArrays[0][i].getFConst());
2109 else
2110 tempConstArray[i].setFConst(-unionArrays[0][i].getFConst());
2111 }
2112 }
2113 else
2114 UNREACHABLE();
2115 break;
2116
2117 case EOpRefract:
2118 if (basicType == EbtFloat)
2119 {
2120 // genType refract(genType I, genType N, float eta) :
2121 // For the incident vector I and surface normal N, and the ratio of indices of refraction eta,
2122 // return the refraction vector. The result is computed by
2123 // k = 1.0 - eta * eta * (1.0 - dot(N, I) * dot(N, I))
2124 // if (k < 0.0)
2125 // return genType(0.0)
2126 // else
2127 // return eta * I - (eta * dot(N, I) + sqrt(k)) * N
2128 tempConstArray = new TConstantUnion[maxObjectSize];
2129 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
2130 for (size_t i = 0; i < maxObjectSize; i++)
2131 {
2132 float eta = unionArrays[2][i].getFConst();
2133 float k = 1.0f - eta * eta * (1.0f - dotProduct * dotProduct);
2134 if (k < 0.0f)
2135 tempConstArray[i].setFConst(0.0f);
2136 else
2137 tempConstArray[i].setFConst(eta * unionArrays[0][i].getFConst() -
2138 (eta * dotProduct + sqrtf(k)) * unionArrays[1][i].getFConst());
2139 }
2140 }
2141 else
2142 UNREACHABLE();
2143 break;
2144
Arun Patole274f0702015-05-05 13:33:30 +05302145 default:
2146 UNREACHABLE();
2147 // TODO: Add constant folding support for other built-in operations that take 3 parameters and not handled above.
2148 return nullptr;
2149 }
2150 }
2151
2152 if (tempConstArray)
2153 {
2154 tempNode = new TIntermConstantUnion(tempConstArray, returnType);
2155 tempNode->setLine(loc);
2156 }
2157 return tempNode;
2158}
2159
2160// static
Jamie Madillb1a85f42014-08-19 15:23:24 -04002161TString TIntermTraverser::hash(const TString &name, ShHashFunction64 hashFunction)
2162{
2163 if (hashFunction == NULL || name.empty())
2164 return name;
2165 khronos_uint64_t number = (*hashFunction)(name.c_str(), name.length());
2166 TStringStream stream;
2167 stream << HASHED_NAME_PREFIX << std::hex << number;
2168 TString hashedName = stream.str();
2169 return hashedName;
2170}
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002171
2172void TIntermTraverser::updateTree()
2173{
Olli Etuahoa6f22092015-05-08 18:31:10 +03002174 for (size_t ii = 0; ii < mInsertions.size(); ++ii)
2175 {
2176 const NodeInsertMultipleEntry &insertion = mInsertions[ii];
2177 ASSERT(insertion.parent);
2178 bool inserted = insertion.parent->insertChildNodes(insertion.position, insertion.insertions);
2179 ASSERT(inserted);
2180 UNUSED_ASSERTION_VARIABLE(inserted);
2181 }
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002182 for (size_t ii = 0; ii < mReplacements.size(); ++ii)
2183 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03002184 const NodeUpdateEntry &replacement = mReplacements[ii];
2185 ASSERT(replacement.parent);
2186 bool replaced = replacement.parent->replaceChildNode(
2187 replacement.original, replacement.replacement);
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002188 ASSERT(replaced);
Olli Etuahod57e0db2015-04-24 15:05:08 +03002189 UNUSED_ASSERTION_VARIABLE(replaced);
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002190
Olli Etuahocd94ef92015-04-16 19:18:10 +03002191 if (!replacement.originalBecomesChildOfReplacement)
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002192 {
2193 // In AST traversing, a parent is visited before its children.
Olli Etuahocd94ef92015-04-16 19:18:10 +03002194 // After we replace a node, if its immediate child is to
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002195 // be replaced, we need to make sure we don't update the replaced
2196 // node; instead, we update the replacement node.
2197 for (size_t jj = ii + 1; jj < mReplacements.size(); ++jj)
2198 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03002199 NodeUpdateEntry &replacement2 = mReplacements[jj];
2200 if (replacement2.parent == replacement.original)
2201 replacement2.parent = replacement.replacement;
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002202 }
2203 }
2204 }
Olli Etuahofc0e2bc2015-04-16 13:39:56 +03002205 for (size_t ii = 0; ii < mMultiReplacements.size(); ++ii)
2206 {
2207 const NodeReplaceWithMultipleEntry &replacement = mMultiReplacements[ii];
2208 ASSERT(replacement.parent);
2209 bool replaced = replacement.parent->replaceChildNodeWithMultiple(
2210 replacement.original, replacement.replacements);
2211 ASSERT(replaced);
Olli Etuahod57e0db2015-04-24 15:05:08 +03002212 UNUSED_ASSERTION_VARIABLE(replaced);
Olli Etuahofc0e2bc2015-04-16 13:39:56 +03002213 }
Olli Etuahod4f303e2015-05-20 17:09:06 +03002214
2215 mInsertions.clear();
2216 mReplacements.clear();
2217 mMultiReplacements.clear();
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002218}