blob: 680ca782dcc33f6514c6aa70eb8a26da31152be3 [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
Jamie Madillb1a85f42014-08-19 15:23:24 -0400769//
770// The fold functions see if an operation on a constant can be done in place,
771// without generating run-time code.
772//
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300773// Returns the constant value to keep using or nullptr.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400774//
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300775TConstantUnion *TIntermConstantUnion::foldBinary(TOperator op, TIntermConstantUnion *rightNode, TInfoSink &infoSink)
776{
777 TConstantUnion *leftArray = getUnionArrayPointer();
778 TConstantUnion *rightArray = rightNode->getUnionArrayPointer();
779
780 if (!leftArray)
781 return nullptr;
782 if (!rightArray)
783 return nullptr;
784
785 size_t objectSize = getType().getObjectSize();
786
787 // for a case like float f = vec4(2, 3, 4, 5) + 1.2;
788 if (rightNode->getType().getObjectSize() == 1 && objectSize > 1)
789 {
790 rightArray = Vectorize(*rightNode->getUnionArrayPointer(), objectSize);
791 }
792 else if (rightNode->getType().getObjectSize() > 1 && objectSize == 1)
793 {
794 // for a case like float f = 1.2 + vec4(2, 3, 4, 5);
795 leftArray = Vectorize(*getUnionArrayPointer(), rightNode->getType().getObjectSize());
796 objectSize = rightNode->getType().getObjectSize();
797 }
798
799 TConstantUnion *resultArray = nullptr;
800
801 switch(op)
802 {
803 case EOpAdd:
804 resultArray = new TConstantUnion[objectSize];
805 for (size_t i = 0; i < objectSize; i++)
806 resultArray[i] = leftArray[i] + rightArray[i];
807 break;
808 case EOpSub:
809 resultArray = new TConstantUnion[objectSize];
810 for (size_t i = 0; i < objectSize; i++)
811 resultArray[i] = leftArray[i] - rightArray[i];
812 break;
813
814 case EOpMul:
815 case EOpVectorTimesScalar:
816 case EOpMatrixTimesScalar:
817 resultArray = new TConstantUnion[objectSize];
818 for (size_t i = 0; i < objectSize; i++)
819 resultArray[i] = leftArray[i] * rightArray[i];
820 break;
821
822 case EOpMatrixTimesMatrix:
823 {
824 if (getType().getBasicType() != EbtFloat ||
825 rightNode->getBasicType() != EbtFloat)
826 {
827 infoSink.info.message(
828 EPrefixInternalError, getLine(),
829 "Constant Folding cannot be done for matrix multiply");
830 return nullptr;
831 }
832
833 const int leftCols = getCols();
834 const int leftRows = getRows();
835 const int rightCols = rightNode->getType().getCols();
836 const int rightRows = rightNode->getType().getRows();
837 const int resultCols = rightCols;
838 const int resultRows = leftRows;
839
840 resultArray = new TConstantUnion[resultCols * resultRows];
841 for (int row = 0; row < resultRows; row++)
842 {
843 for (int column = 0; column < resultCols; column++)
844 {
845 resultArray[resultRows * column + row].setFConst(0.0f);
846 for (int i = 0; i < leftCols; i++)
847 {
848 resultArray[resultRows * column + row].setFConst(
849 resultArray[resultRows * column + row].getFConst() +
850 leftArray[i * leftRows + row].getFConst() *
851 rightArray[column * rightRows + i].getFConst());
852 }
853 }
854 }
855 }
856 break;
857
858 case EOpDiv:
859 case EOpIMod:
860 {
861 resultArray = new TConstantUnion[objectSize];
862 for (size_t i = 0; i < objectSize; i++)
863 {
864 switch (getType().getBasicType())
865 {
866 case EbtFloat:
867 if (rightArray[i] == 0.0f)
868 {
869 infoSink.info.message(EPrefixWarning, getLine(),
870 "Divide by zero error during constant folding");
871 resultArray[i].setFConst(leftArray[i].getFConst() < 0 ? -FLT_MAX : FLT_MAX);
872 }
873 else
874 {
875 ASSERT(op == EOpDiv);
876 resultArray[i].setFConst(leftArray[i].getFConst() / rightArray[i].getFConst());
877 }
878 break;
879
880 case EbtInt:
881 if (rightArray[i] == 0)
882 {
883 infoSink.info.message(EPrefixWarning, getLine(),
884 "Divide by zero error during constant folding");
885 resultArray[i].setIConst(INT_MAX);
886 }
887 else
888 {
889 if (op == EOpDiv)
890 {
891 resultArray[i].setIConst(leftArray[i].getIConst() / rightArray[i].getIConst());
892 }
893 else
894 {
895 ASSERT(op == EOpIMod);
896 resultArray[i].setIConst(leftArray[i].getIConst() % rightArray[i].getIConst());
897 }
898 }
899 break;
900
901 case EbtUInt:
902 if (rightArray[i] == 0)
903 {
904 infoSink.info.message(EPrefixWarning, getLine(),
905 "Divide by zero error during constant folding");
906 resultArray[i].setUConst(UINT_MAX);
907 }
908 else
909 {
910 if (op == EOpDiv)
911 {
912 resultArray[i].setUConst(leftArray[i].getUConst() / rightArray[i].getUConst());
913 }
914 else
915 {
916 ASSERT(op == EOpIMod);
917 resultArray[i].setUConst(leftArray[i].getUConst() % rightArray[i].getUConst());
918 }
919 }
920 break;
921
922 default:
923 infoSink.info.message(EPrefixInternalError, getLine(),
924 "Constant folding cannot be done for \"/\"");
925 return nullptr;
926 }
927 }
928 }
929 break;
930
931 case EOpMatrixTimesVector:
932 {
933 if (rightNode->getBasicType() != EbtFloat)
934 {
935 infoSink.info.message(EPrefixInternalError, getLine(),
936 "Constant Folding cannot be done for matrix times vector");
937 return nullptr;
938 }
939
940 const int matrixCols = getCols();
941 const int matrixRows = getRows();
942
943 resultArray = new TConstantUnion[matrixRows];
944
945 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
946 {
947 resultArray[matrixRow].setFConst(0.0f);
948 for (int col = 0; col < matrixCols; col++)
949 {
950 resultArray[matrixRow].setFConst(resultArray[matrixRow].getFConst() +
951 leftArray[col * matrixRows + matrixRow].getFConst() *
952 rightArray[col].getFConst());
953 }
954 }
955 }
956 break;
957
958 case EOpVectorTimesMatrix:
959 {
960 if (getType().getBasicType() != EbtFloat)
961 {
962 infoSink.info.message(EPrefixInternalError, getLine(),
963 "Constant Folding cannot be done for vector times matrix");
964 return nullptr;
965 }
966
967 const int matrixCols = rightNode->getType().getCols();
968 const int matrixRows = rightNode->getType().getRows();
969
970 resultArray = new TConstantUnion[matrixCols];
971
972 for (int matrixCol = 0; matrixCol < matrixCols; matrixCol++)
973 {
974 resultArray[matrixCol].setFConst(0.0f);
975 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
976 {
977 resultArray[matrixCol].setFConst(resultArray[matrixCol].getFConst() +
978 leftArray[matrixRow].getFConst() *
979 rightArray[matrixCol * matrixRows + matrixRow].getFConst());
980 }
981 }
982 }
983 break;
984
985 case EOpLogicalAnd:
986 {
987 resultArray = new TConstantUnion[objectSize];
988 for (size_t i = 0; i < objectSize; i++)
989 {
990 resultArray[i] = leftArray[i] && rightArray[i];
991 }
992 }
993 break;
994
995 case EOpLogicalOr:
996 {
997 resultArray = new TConstantUnion[objectSize];
998 for (size_t i = 0; i < objectSize; i++)
999 {
1000 resultArray[i] = leftArray[i] || rightArray[i];
1001 }
1002 }
1003 break;
1004
1005 case EOpLogicalXor:
1006 {
1007 resultArray = new TConstantUnion[objectSize];
1008 for (size_t i = 0; i < objectSize; i++)
1009 {
1010 switch (getType().getBasicType())
1011 {
1012 case EbtBool:
1013 resultArray[i].setBConst(leftArray[i] != rightArray[i]);
1014 break;
1015 default:
1016 UNREACHABLE();
1017 break;
1018 }
1019 }
1020 }
1021 break;
1022
1023 case EOpBitwiseAnd:
1024 resultArray = new TConstantUnion[objectSize];
1025 for (size_t i = 0; i < objectSize; i++)
1026 resultArray[i] = leftArray[i] & rightArray[i];
1027 break;
1028 case EOpBitwiseXor:
1029 resultArray = new TConstantUnion[objectSize];
1030 for (size_t i = 0; i < objectSize; i++)
1031 resultArray[i] = leftArray[i] ^ rightArray[i];
1032 break;
1033 case EOpBitwiseOr:
1034 resultArray = new TConstantUnion[objectSize];
1035 for (size_t i = 0; i < objectSize; i++)
1036 resultArray[i] = leftArray[i] | rightArray[i];
1037 break;
1038 case EOpBitShiftLeft:
1039 resultArray = new TConstantUnion[objectSize];
1040 for (size_t i = 0; i < objectSize; i++)
1041 resultArray[i] = leftArray[i] << rightArray[i];
1042 break;
1043 case EOpBitShiftRight:
1044 resultArray = new TConstantUnion[objectSize];
1045 for (size_t i = 0; i < objectSize; i++)
1046 resultArray[i] = leftArray[i] >> rightArray[i];
1047 break;
1048
1049 case EOpLessThan:
1050 ASSERT(objectSize == 1);
1051 resultArray = new TConstantUnion[1];
1052 resultArray->setBConst(*leftArray < *rightArray);
1053 break;
1054
1055 case EOpGreaterThan:
1056 ASSERT(objectSize == 1);
1057 resultArray = new TConstantUnion[1];
1058 resultArray->setBConst(*leftArray > *rightArray);
1059 break;
1060
1061 case EOpLessThanEqual:
1062 ASSERT(objectSize == 1);
1063 resultArray = new TConstantUnion[1];
1064 resultArray->setBConst(!(*leftArray > *rightArray));
1065 break;
1066
1067 case EOpGreaterThanEqual:
1068 ASSERT(objectSize == 1);
1069 resultArray = new TConstantUnion[1];
1070 resultArray->setBConst(!(*leftArray < *rightArray));
1071 break;
1072
1073 case EOpEqual:
1074 case EOpNotEqual:
1075 {
1076 resultArray = new TConstantUnion[1];
1077 bool equal = true;
1078 if (getType().getBasicType() == EbtStruct)
1079 {
1080 equal = CompareStructure(getType(), rightArray, leftArray);
1081 }
1082 else
1083 {
1084 for (size_t i = 0; i < objectSize; i++)
1085 {
1086 if (leftArray[i] != rightArray[i])
1087 {
1088 equal = false;
1089 break; // break out of for loop
1090 }
1091 }
1092 }
1093 if (op == EOpEqual)
1094 {
1095 resultArray->setBConst(equal);
1096 }
1097 else
1098 {
1099 resultArray->setBConst(!equal);
1100 }
1101 }
1102 break;
1103
1104 default:
1105 infoSink.info.message(
1106 EPrefixInternalError, getLine(),
1107 "Invalid operator for constant folding");
1108 return nullptr;
1109 }
1110 return resultArray;
1111}
1112
1113//
1114// The fold functions see if an operation on a constant can be done in place,
1115// without generating run-time code.
1116//
1117// Returns the node to keep using or nullptr.
1118//
1119TIntermTyped *TIntermConstantUnion::foldUnary(TOperator op, TInfoSink &infoSink)
Jamie Madillb1a85f42014-08-19 15:23:24 -04001120{
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001121 TConstantUnion *unionArray = getUnionArrayPointer();
Jamie Madillb1a85f42014-08-19 15:23:24 -04001122
1123 if (!unionArray)
Arun Patolefddc2112015-04-22 13:28:10 +05301124 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001125
1126 size_t objectSize = getType().getObjectSize();
1127
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001128 if (op == EOpAny || op == EOpAll || op == EOpLength)
Arun Patole9d0b1f92015-05-20 14:27:17 +05301129 {
1130 // Do operations where the return type is different from the operand type.
1131
Arun Patole1155ddd2015-06-05 18:04:36 +05301132 TType returnType;
Arun Patole9d0b1f92015-05-20 14:27:17 +05301133 TConstantUnion *tempConstArray = nullptr;
Arun Patole1155ddd2015-06-05 18:04:36 +05301134 switch (op)
Arun Patole9d0b1f92015-05-20 14:27:17 +05301135 {
Arun Patole1155ddd2015-06-05 18:04:36 +05301136 case EOpAny:
Arun Patole9d0b1f92015-05-20 14:27:17 +05301137 if (getType().getBasicType() == EbtBool)
1138 {
1139 tempConstArray = new TConstantUnion();
1140 tempConstArray->setBConst(false);
1141 for (size_t i = 0; i < objectSize; i++)
1142 {
1143 if (unionArray[i].getBConst())
1144 {
1145 tempConstArray->setBConst(true);
1146 break;
1147 }
1148 }
Arun Patole1155ddd2015-06-05 18:04:36 +05301149 returnType = TType(EbtBool, EbpUndefined, EvqConst);
1150 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05301151 }
1152 else
1153 {
Arun Patole1155ddd2015-06-05 18:04:36 +05301154 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
Arun Patole9d0b1f92015-05-20 14:27:17 +05301155 return nullptr;
1156 }
Arun Patole1155ddd2015-06-05 18:04:36 +05301157
1158 case EOpAll:
Arun Patole9d0b1f92015-05-20 14:27:17 +05301159 if (getType().getBasicType() == EbtBool)
1160 {
1161 tempConstArray = new TConstantUnion();
1162 tempConstArray->setBConst(true);
1163 for (size_t i = 0; i < objectSize; i++)
1164 {
1165 if (!unionArray[i].getBConst())
1166 {
1167 tempConstArray->setBConst(false);
1168 break;
1169 }
1170 }
Arun Patole1155ddd2015-06-05 18:04:36 +05301171 returnType = TType(EbtBool, EbpUndefined, EvqConst);
1172 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05301173 }
1174 else
1175 {
Arun Patole1155ddd2015-06-05 18:04:36 +05301176 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
Arun Patole9d0b1f92015-05-20 14:27:17 +05301177 return nullptr;
1178 }
Arun Patole1155ddd2015-06-05 18:04:36 +05301179
1180 case EOpLength:
1181 if (getType().getBasicType() == EbtFloat)
1182 {
1183 tempConstArray = new TConstantUnion();
1184 tempConstArray->setFConst(VectorLength(unionArray, objectSize));
1185 returnType = TType(EbtFloat, getType().getPrecision(), EvqConst);
1186 break;
1187 }
1188 else
1189 {
1190 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1191 return nullptr;
1192 }
1193
1194 default:
1195 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05301196 }
Arun Patole1155ddd2015-06-05 18:04:36 +05301197
Arun Patole9d0b1f92015-05-20 14:27:17 +05301198 TIntermConstantUnion *tempNode = new TIntermConstantUnion(tempConstArray, returnType);
1199 tempNode->setLine(getLine());
1200 return tempNode;
1201 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04001202 else
1203 {
1204 //
Arun Patole9d0b1f92015-05-20 14:27:17 +05301205 // Do unary operations where the return type is the same as operand type.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001206 //
1207 TIntermConstantUnion *newNode = 0;
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001208 TConstantUnion* tempConstArray = new TConstantUnion[objectSize];
Jamie Madillb1a85f42014-08-19 15:23:24 -04001209 for (size_t i = 0; i < objectSize; i++)
1210 {
1211 switch(op)
1212 {
1213 case EOpNegative:
1214 switch (getType().getBasicType())
1215 {
1216 case EbtFloat:
1217 tempConstArray[i].setFConst(-unionArray[i].getFConst());
1218 break;
1219 case EbtInt:
1220 tempConstArray[i].setIConst(-unionArray[i].getIConst());
1221 break;
1222 case EbtUInt:
1223 tempConstArray[i].setUConst(static_cast<unsigned int>(
1224 -static_cast<int>(unionArray[i].getUConst())));
1225 break;
1226 default:
1227 infoSink.info.message(
1228 EPrefixInternalError, getLine(),
1229 "Unary operation not folded into constant");
Arun Patolefddc2112015-04-22 13:28:10 +05301230 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001231 }
1232 break;
1233
Zhenyao Mode1e00e2014-10-09 16:55:32 -07001234 case EOpPositive:
1235 switch (getType().getBasicType())
1236 {
1237 case EbtFloat:
1238 tempConstArray[i].setFConst(unionArray[i].getFConst());
1239 break;
1240 case EbtInt:
1241 tempConstArray[i].setIConst(unionArray[i].getIConst());
1242 break;
1243 case EbtUInt:
1244 tempConstArray[i].setUConst(static_cast<unsigned int>(
1245 static_cast<int>(unionArray[i].getUConst())));
1246 break;
1247 default:
1248 infoSink.info.message(
1249 EPrefixInternalError, getLine(),
1250 "Unary operation not folded into constant");
Arun Patolefddc2112015-04-22 13:28:10 +05301251 return nullptr;
Zhenyao Mode1e00e2014-10-09 16:55:32 -07001252 }
1253 break;
1254
Jamie Madillb1a85f42014-08-19 15:23:24 -04001255 case EOpLogicalNot:
1256 // this code is written for possible future use,
1257 // will not get executed currently
1258 switch (getType().getBasicType())
1259 {
1260 case EbtBool:
1261 tempConstArray[i].setBConst(!unionArray[i].getBConst());
1262 break;
1263 default:
1264 infoSink.info.message(
1265 EPrefixInternalError, getLine(),
1266 "Unary operation not folded into constant");
Arun Patolefddc2112015-04-22 13:28:10 +05301267 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001268 }
1269 break;
1270
Olli Etuaho31b5fc62015-01-16 12:13:36 +02001271 case EOpBitwiseNot:
1272 switch (getType().getBasicType())
1273 {
1274 case EbtInt:
1275 tempConstArray[i].setIConst(~unionArray[i].getIConst());
1276 break;
1277 case EbtUInt:
1278 tempConstArray[i].setUConst(~unionArray[i].getUConst());
1279 break;
1280 default:
1281 infoSink.info.message(
1282 EPrefixInternalError, getLine(),
1283 "Unary operation not folded into constant");
Arun Patolefddc2112015-04-22 13:28:10 +05301284 return nullptr;
Olli Etuaho31b5fc62015-01-16 12:13:36 +02001285 }
1286 break;
1287
Arun Patole9dea48f2015-04-02 11:45:09 +05301288 case EOpRadians:
1289 if (getType().getBasicType() == EbtFloat)
1290 {
1291 tempConstArray[i].setFConst(kDegreesToRadiansMultiplier * unionArray[i].getFConst());
1292 break;
1293 }
1294 infoSink.info.message(
1295 EPrefixInternalError, getLine(),
1296 "Unary operation not folded into constant");
1297 return nullptr;
1298
1299 case EOpDegrees:
1300 if (getType().getBasicType() == EbtFloat)
1301 {
1302 tempConstArray[i].setFConst(kRadiansToDegreesMultiplier * unionArray[i].getFConst());
1303 break;
1304 }
1305 infoSink.info.message(
1306 EPrefixInternalError, getLine(),
1307 "Unary operation not folded into constant");
1308 return nullptr;
1309
1310 case EOpSin:
1311 if (!foldFloatTypeUnary(unionArray[i], &sinf, infoSink, &tempConstArray[i]))
1312 return nullptr;
1313 break;
1314
1315 case EOpCos:
1316 if (!foldFloatTypeUnary(unionArray[i], &cosf, infoSink, &tempConstArray[i]))
1317 return nullptr;
1318 break;
1319
1320 case EOpTan:
1321 if (!foldFloatTypeUnary(unionArray[i], &tanf, infoSink, &tempConstArray[i]))
1322 return nullptr;
1323 break;
1324
1325 case EOpAsin:
1326 // For asin(x), results are undefined if |x| > 1, we are choosing to set result to 0.
1327 if (getType().getBasicType() == EbtFloat && fabsf(unionArray[i].getFConst()) > 1.0f)
Arun Patole081c3f22015-05-25 15:43:35 +05301328 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &tempConstArray[i]);
Arun Patole9dea48f2015-04-02 11:45:09 +05301329 else if (!foldFloatTypeUnary(unionArray[i], &asinf, infoSink, &tempConstArray[i]))
1330 return nullptr;
1331 break;
1332
1333 case EOpAcos:
1334 // For acos(x), results are undefined if |x| > 1, we are choosing to set result to 0.
1335 if (getType().getBasicType() == EbtFloat && fabsf(unionArray[i].getFConst()) > 1.0f)
Arun Patole081c3f22015-05-25 15:43:35 +05301336 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &tempConstArray[i]);
Arun Patole9dea48f2015-04-02 11:45:09 +05301337 else if (!foldFloatTypeUnary(unionArray[i], &acosf, infoSink, &tempConstArray[i]))
1338 return nullptr;
1339 break;
1340
1341 case EOpAtan:
1342 if (!foldFloatTypeUnary(unionArray[i], &atanf, infoSink, &tempConstArray[i]))
1343 return nullptr;
1344 break;
1345
1346 case EOpSinh:
1347 if (!foldFloatTypeUnary(unionArray[i], &sinhf, infoSink, &tempConstArray[i]))
1348 return nullptr;
1349 break;
1350
1351 case EOpCosh:
1352 if (!foldFloatTypeUnary(unionArray[i], &coshf, infoSink, &tempConstArray[i]))
1353 return nullptr;
1354 break;
1355
1356 case EOpTanh:
1357 if (!foldFloatTypeUnary(unionArray[i], &tanhf, infoSink, &tempConstArray[i]))
1358 return nullptr;
1359 break;
1360
1361 case EOpAsinh:
1362 if (!foldFloatTypeUnary(unionArray[i], &asinhf, infoSink, &tempConstArray[i]))
1363 return nullptr;
1364 break;
1365
1366 case EOpAcosh:
1367 // For acosh(x), results are undefined if x < 1, we are choosing to set result to 0.
1368 if (getType().getBasicType() == EbtFloat && unionArray[i].getFConst() < 1.0f)
Arun Patole081c3f22015-05-25 15:43:35 +05301369 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &tempConstArray[i]);
Arun Patole9dea48f2015-04-02 11:45:09 +05301370 else if (!foldFloatTypeUnary(unionArray[i], &acoshf, infoSink, &tempConstArray[i]))
1371 return nullptr;
1372 break;
1373
1374 case EOpAtanh:
1375 // For atanh(x), results are undefined if |x| >= 1, we are choosing to set result to 0.
1376 if (getType().getBasicType() == EbtFloat && fabsf(unionArray[i].getFConst()) >= 1.0f)
Arun Patole081c3f22015-05-25 15:43:35 +05301377 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &tempConstArray[i]);
Arun Patole9dea48f2015-04-02 11:45:09 +05301378 else if (!foldFloatTypeUnary(unionArray[i], &atanhf, infoSink, &tempConstArray[i]))
1379 return nullptr;
1380 break;
1381
Arun Patole97dc22e2015-04-06 17:35:38 +05301382 case EOpAbs:
1383 switch (getType().getBasicType())
1384 {
1385 case EbtFloat:
1386 tempConstArray[i].setFConst(fabsf(unionArray[i].getFConst()));
1387 break;
1388 case EbtInt:
1389 tempConstArray[i].setIConst(abs(unionArray[i].getIConst()));
1390 break;
1391 default:
1392 infoSink.info.message(
1393 EPrefixInternalError, getLine(),
1394 "Unary operation not folded into constant");
1395 return nullptr;
1396 }
1397 break;
1398
1399 case EOpSign:
1400 switch (getType().getBasicType())
1401 {
1402 case EbtFloat:
1403 {
1404 float fConst = unionArray[i].getFConst();
1405 float fResult = 0.0f;
1406 if (fConst > 0.0f)
1407 fResult = 1.0f;
1408 else if (fConst < 0.0f)
1409 fResult = -1.0f;
1410 tempConstArray[i].setFConst(fResult);
1411 }
1412 break;
1413 case EbtInt:
1414 {
1415 int iConst = unionArray[i].getIConst();
1416 int iResult = 0;
1417 if (iConst > 0)
1418 iResult = 1;
1419 else if (iConst < 0)
1420 iResult = -1;
1421 tempConstArray[i].setIConst(iResult);
1422 }
1423 break;
1424 default:
1425 infoSink.info.message(
1426 EPrefixInternalError, getLine(),
1427 "Unary operation not folded into constant");
1428 return nullptr;
1429 }
1430 break;
1431
1432 case EOpFloor:
1433 if (!foldFloatTypeUnary(unionArray[i], &floorf, infoSink, &tempConstArray[i]))
1434 return nullptr;
1435 break;
1436
1437 case EOpTrunc:
1438 if (!foldFloatTypeUnary(unionArray[i], &truncf, infoSink, &tempConstArray[i]))
1439 return nullptr;
1440 break;
1441
1442 case EOpRound:
1443 if (!foldFloatTypeUnary(unionArray[i], &roundf, infoSink, &tempConstArray[i]))
1444 return nullptr;
1445 break;
1446
1447 case EOpRoundEven:
1448 if (getType().getBasicType() == EbtFloat)
1449 {
1450 float x = unionArray[i].getFConst();
1451 float result;
1452 float fractPart = modff(x, &result);
1453 if (fabsf(fractPart) == 0.5f)
1454 result = 2.0f * roundf(x / 2.0f);
1455 else
1456 result = roundf(x);
1457 tempConstArray[i].setFConst(result);
1458 break;
1459 }
1460 infoSink.info.message(
1461 EPrefixInternalError, getLine(),
1462 "Unary operation not folded into constant");
1463 return nullptr;
1464
1465 case EOpCeil:
1466 if (!foldFloatTypeUnary(unionArray[i], &ceilf, infoSink, &tempConstArray[i]))
1467 return nullptr;
1468 break;
1469
1470 case EOpFract:
1471 if (getType().getBasicType() == EbtFloat)
1472 {
1473 float x = unionArray[i].getFConst();
1474 tempConstArray[i].setFConst(x - floorf(x));
1475 break;
1476 }
1477 infoSink.info.message(
1478 EPrefixInternalError, getLine(),
1479 "Unary operation not folded into constant");
1480 return nullptr;
1481
Arun Patole28eb65e2015-04-06 17:29:48 +05301482 case EOpExp:
1483 if (!foldFloatTypeUnary(unionArray[i], &expf, infoSink, &tempConstArray[i]))
1484 return nullptr;
1485 break;
1486
1487 case EOpLog:
1488 // For log(x), results are undefined if x <= 0, we are choosing to set result to 0.
1489 if (getType().getBasicType() == EbtFloat && unionArray[i].getFConst() <= 0.0f)
Arun Patole081c3f22015-05-25 15:43:35 +05301490 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &tempConstArray[i]);
Arun Patole28eb65e2015-04-06 17:29:48 +05301491 else if (!foldFloatTypeUnary(unionArray[i], &logf, infoSink, &tempConstArray[i]))
1492 return nullptr;
1493 break;
1494
1495 case EOpExp2:
1496 if (!foldFloatTypeUnary(unionArray[i], &exp2f, infoSink, &tempConstArray[i]))
1497 return nullptr;
1498 break;
1499
1500 case EOpLog2:
1501 // For log2(x), results are undefined if x <= 0, we are choosing to set result to 0.
1502 // And log2f is not available on some plarforms like old android, so just using log(x)/log(2) here.
1503 if (getType().getBasicType() == EbtFloat && unionArray[i].getFConst() <= 0.0f)
Arun Patole081c3f22015-05-25 15:43:35 +05301504 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &tempConstArray[i]);
Arun Patole28eb65e2015-04-06 17:29:48 +05301505 else if (!foldFloatTypeUnary(unionArray[i], &logf, infoSink, &tempConstArray[i]))
1506 return nullptr;
1507 else
1508 tempConstArray[i].setFConst(tempConstArray[i].getFConst() / logf(2.0f));
1509 break;
1510
1511 case EOpSqrt:
1512 // For sqrt(x), results are undefined if x < 0, we are choosing to set result to 0.
1513 if (getType().getBasicType() == EbtFloat && unionArray[i].getFConst() < 0.0f)
Arun Patole081c3f22015-05-25 15:43:35 +05301514 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &tempConstArray[i]);
Arun Patole28eb65e2015-04-06 17:29:48 +05301515 else if (!foldFloatTypeUnary(unionArray[i], &sqrtf, infoSink, &tempConstArray[i]))
1516 return nullptr;
1517 break;
1518
1519 case EOpInverseSqrt:
1520 // There is no stdlib built-in function equavalent for GLES built-in inversesqrt(),
1521 // so getting the square root first using builtin function sqrt() and then taking its inverse.
1522 // Also, for inversesqrt(x), results are undefined if x <= 0, we are choosing to set result to 0.
1523 if (getType().getBasicType() == EbtFloat && unionArray[i].getFConst() <= 0.0f)
Arun Patole081c3f22015-05-25 15:43:35 +05301524 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &tempConstArray[i]);
Arun Patole28eb65e2015-04-06 17:29:48 +05301525 else if (!foldFloatTypeUnary(unionArray[i], &sqrtf, infoSink, &tempConstArray[i]))
1526 return nullptr;
1527 else
1528 tempConstArray[i].setFConst(1.0f / tempConstArray[i].getFConst());
1529 break;
1530
Arun Patole9d0b1f92015-05-20 14:27:17 +05301531 case EOpVectorLogicalNot:
1532 if (getType().getBasicType() == EbtBool)
1533 {
1534 tempConstArray[i].setBConst(!unionArray[i].getBConst());
1535 break;
1536 }
1537 infoSink.info.message(
1538 EPrefixInternalError, getLine(),
1539 "Unary operation not folded into constant");
1540 return nullptr;
1541
Arun Patole1155ddd2015-06-05 18:04:36 +05301542 case EOpNormalize:
1543 if (getType().getBasicType() == EbtFloat)
1544 {
1545 float x = unionArray[i].getFConst();
1546 float length = VectorLength(unionArray, objectSize);
1547 if (length)
1548 tempConstArray[i].setFConst(x / length);
1549 else
1550 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &tempConstArray[i]);
1551 break;
1552 }
1553 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1554 return nullptr;
1555
Jamie Madillb1a85f42014-08-19 15:23:24 -04001556 default:
Arun Patolefddc2112015-04-22 13:28:10 +05301557 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001558 }
1559 }
1560 newNode = new TIntermConstantUnion(tempConstArray, getType());
1561 newNode->setLine(getLine());
1562 return newNode;
1563 }
1564}
1565
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001566bool TIntermConstantUnion::foldFloatTypeUnary(const TConstantUnion &parameter, FloatTypeUnaryFunc builtinFunc,
1567 TInfoSink &infoSink, TConstantUnion *result) const
Arun Patole9dea48f2015-04-02 11:45:09 +05301568{
1569 ASSERT(builtinFunc);
1570
1571 if (getType().getBasicType() == EbtFloat)
1572 {
1573 result->setFConst(builtinFunc(parameter.getFConst()));
1574 return true;
1575 }
1576
1577 infoSink.info.message(
1578 EPrefixInternalError, getLine(),
1579 "Unary operation not folded into constant");
1580 return false;
1581}
1582
Jamie Madillb1a85f42014-08-19 15:23:24 -04001583// static
Arun Patolebf790422015-05-18 17:53:04 +05301584TIntermTyped *TIntermConstantUnion::FoldAggregateBuiltIn(TOperator op, TIntermAggregate *aggregate, TInfoSink &infoSink)
Arun Patole274f0702015-05-05 13:33:30 +05301585{
1586 TIntermSequence *sequence = aggregate->getSequence();
1587 unsigned int paramsCount = sequence->size();
1588 std::vector<TConstantUnion *> unionArrays(paramsCount);
1589 std::vector<size_t> objectSizes(paramsCount);
1590 TType *maxSizeType = nullptr;
1591 TBasicType basicType = EbtVoid;
1592 TSourceLoc loc;
1593 for (unsigned int i = 0; i < paramsCount; i++)
1594 {
1595 TIntermConstantUnion *paramConstant = (*sequence)[i]->getAsConstantUnion();
1596 // Make sure that all params are constant before actual constant folding.
1597 if (!paramConstant)
1598 return nullptr;
1599
1600 if (i == 0)
1601 {
1602 basicType = paramConstant->getType().getBasicType();
1603 loc = paramConstant->getLine();
1604 }
1605 unionArrays[i] = paramConstant->getUnionArrayPointer();
1606 objectSizes[i] = paramConstant->getType().getObjectSize();
1607 if (maxSizeType == nullptr || (objectSizes[i] >= maxSizeType->getObjectSize()))
1608 maxSizeType = paramConstant->getTypePointer();
1609 }
1610
1611 size_t maxObjectSize = maxSizeType->getObjectSize();
1612 for (unsigned int i = 0; i < paramsCount; i++)
1613 if (objectSizes[i] != maxObjectSize)
1614 unionArrays[i] = Vectorize(*unionArrays[i], maxObjectSize);
1615
1616 TConstantUnion *tempConstArray = nullptr;
1617 TIntermConstantUnion *tempNode = nullptr;
1618 TType returnType = *maxSizeType;
1619 if (paramsCount == 2)
1620 {
1621 //
1622 // Binary built-in
1623 //
1624 switch (op)
1625 {
Arun Patolebf790422015-05-18 17:53:04 +05301626 case EOpAtan:
1627 {
1628 if (basicType == EbtFloat)
1629 {
1630 tempConstArray = new TConstantUnion[maxObjectSize];
1631 for (size_t i = 0; i < maxObjectSize; i++)
1632 {
1633 float y = unionArrays[0][i].getFConst();
1634 float x = unionArrays[1][i].getFConst();
1635 // Results are undefined if x and y are both 0.
1636 if (x == 0.0f && y == 0.0f)
1637 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &tempConstArray[i]);
1638 else
1639 tempConstArray[i].setFConst(atan2f(y, x));
1640 }
1641 }
1642 else
1643 UNREACHABLE();
1644 }
1645 break;
1646
1647 case EOpPow:
1648 {
1649 if (basicType == EbtFloat)
1650 {
1651 tempConstArray = new TConstantUnion[maxObjectSize];
1652 for (size_t i = 0; i < maxObjectSize; i++)
1653 {
1654 float x = unionArrays[0][i].getFConst();
1655 float y = unionArrays[1][i].getFConst();
1656 // Results are undefined if x < 0.
1657 // Results are undefined if x = 0 and y <= 0.
1658 if (x < 0.0f)
1659 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &tempConstArray[i]);
1660 else if (x == 0.0f && y <= 0.0f)
1661 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &tempConstArray[i]);
1662 else
1663 tempConstArray[i].setFConst(powf(x, y));
1664 }
1665 }
1666 else
1667 UNREACHABLE();
1668 }
1669 break;
1670
1671 case EOpMod:
1672 {
1673 if (basicType == EbtFloat)
1674 {
1675 tempConstArray = new TConstantUnion[maxObjectSize];
1676 for (size_t i = 0; i < maxObjectSize; i++)
1677 {
1678 float x = unionArrays[0][i].getFConst();
1679 float y = unionArrays[1][i].getFConst();
1680 tempConstArray[i].setFConst(x - y * floorf(x / y));
1681 }
1682 }
1683 else
1684 UNREACHABLE();
1685 }
1686 break;
1687
Arun Patole274f0702015-05-05 13:33:30 +05301688 case EOpMin:
1689 {
1690 tempConstArray = new TConstantUnion[maxObjectSize];
1691 for (size_t i = 0; i < maxObjectSize; i++)
1692 {
1693 switch (basicType)
1694 {
1695 case EbtFloat:
1696 tempConstArray[i].setFConst(std::min(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
1697 break;
1698 case EbtInt:
1699 tempConstArray[i].setIConst(std::min(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
1700 break;
1701 case EbtUInt:
1702 tempConstArray[i].setUConst(std::min(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
1703 break;
1704 default:
1705 UNREACHABLE();
1706 break;
1707 }
1708 }
1709 }
1710 break;
1711
1712 case EOpMax:
1713 {
1714 tempConstArray = new TConstantUnion[maxObjectSize];
1715 for (size_t i = 0; i < maxObjectSize; i++)
1716 {
1717 switch (basicType)
1718 {
1719 case EbtFloat:
1720 tempConstArray[i].setFConst(std::max(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
1721 break;
1722 case EbtInt:
1723 tempConstArray[i].setIConst(std::max(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
1724 break;
1725 case EbtUInt:
1726 tempConstArray[i].setUConst(std::max(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
1727 break;
1728 default:
1729 UNREACHABLE();
1730 break;
1731 }
1732 }
1733 }
1734 break;
1735
Arun Patolebf790422015-05-18 17:53:04 +05301736 case EOpStep:
1737 {
1738 if (basicType == EbtFloat)
1739 {
1740 tempConstArray = new TConstantUnion[maxObjectSize];
1741 for (size_t i = 0; i < maxObjectSize; i++)
1742 tempConstArray[i].setFConst(unionArrays[1][i].getFConst() < unionArrays[0][i].getFConst() ? 0.0f : 1.0f);
1743 }
1744 else
1745 UNREACHABLE();
1746 }
1747 break;
1748
Arun Patole9d0b1f92015-05-20 14:27:17 +05301749 case EOpLessThan:
1750 {
1751 tempConstArray = new TConstantUnion[maxObjectSize];
1752 for (size_t i = 0; i < maxObjectSize; i++)
1753 {
1754 switch (basicType)
1755 {
1756 case EbtFloat:
1757 tempConstArray[i].setBConst(unionArrays[0][i].getFConst() < unionArrays[1][i].getFConst());
1758 break;
1759 case EbtInt:
1760 tempConstArray[i].setBConst(unionArrays[0][i].getIConst() < unionArrays[1][i].getIConst());
1761 break;
1762 case EbtUInt:
1763 tempConstArray[i].setBConst(unionArrays[0][i].getUConst() < unionArrays[1][i].getUConst());
1764 break;
1765 default:
1766 UNREACHABLE();
1767 break;
1768 }
1769 }
1770 }
1771 break;
1772
1773 case EOpLessThanEqual:
1774 {
1775 tempConstArray = new TConstantUnion[maxObjectSize];
1776 for (size_t i = 0; i < maxObjectSize; i++)
1777 {
1778 switch (basicType)
1779 {
1780 case EbtFloat:
1781 tempConstArray[i].setBConst(unionArrays[0][i].getFConst() <= unionArrays[1][i].getFConst());
1782 break;
1783 case EbtInt:
1784 tempConstArray[i].setBConst(unionArrays[0][i].getIConst() <= unionArrays[1][i].getIConst());
1785 break;
1786 case EbtUInt:
1787 tempConstArray[i].setBConst(unionArrays[0][i].getUConst() <= unionArrays[1][i].getUConst());
1788 break;
1789 default:
1790 UNREACHABLE();
1791 break;
1792 }
1793 }
1794 }
1795 break;
1796
1797 case EOpGreaterThan:
1798 {
1799 tempConstArray = new TConstantUnion[maxObjectSize];
1800 for (size_t i = 0; i < maxObjectSize; i++)
1801 {
1802 switch (basicType)
1803 {
1804 case EbtFloat:
1805 tempConstArray[i].setBConst(unionArrays[0][i].getFConst() > unionArrays[1][i].getFConst());
1806 break;
1807 case EbtInt:
1808 tempConstArray[i].setBConst(unionArrays[0][i].getIConst() > unionArrays[1][i].getIConst());
1809 break;
1810 case EbtUInt:
1811 tempConstArray[i].setBConst(unionArrays[0][i].getUConst() > unionArrays[1][i].getUConst());
1812 break;
1813 default:
1814 UNREACHABLE();
1815 break;
1816 }
1817 }
1818 }
1819 break;
1820
1821 case EOpGreaterThanEqual:
1822 {
1823 tempConstArray = new TConstantUnion[maxObjectSize];
1824 for (size_t i = 0; i < maxObjectSize; i++)
1825 {
1826 switch (basicType)
1827 {
1828 case EbtFloat:
1829 tempConstArray[i].setBConst(unionArrays[0][i].getFConst() >= unionArrays[1][i].getFConst());
1830 break;
1831 case EbtInt:
1832 tempConstArray[i].setBConst(unionArrays[0][i].getIConst() >= unionArrays[1][i].getIConst());
1833 break;
1834 case EbtUInt:
1835 tempConstArray[i].setBConst(unionArrays[0][i].getUConst() >= unionArrays[1][i].getUConst());
1836 break;
1837 default:
1838 UNREACHABLE();
1839 break;
1840 }
1841 }
1842 }
1843 break;
1844
1845 case EOpVectorEqual:
1846 {
1847 tempConstArray = new TConstantUnion[maxObjectSize];
1848 for (size_t i = 0; i < maxObjectSize; i++)
1849 {
1850 switch (basicType)
1851 {
1852 case EbtFloat:
1853 tempConstArray[i].setBConst(unionArrays[0][i].getFConst() == unionArrays[1][i].getFConst());
1854 break;
1855 case EbtInt:
1856 tempConstArray[i].setBConst(unionArrays[0][i].getIConst() == unionArrays[1][i].getIConst());
1857 break;
1858 case EbtUInt:
1859 tempConstArray[i].setBConst(unionArrays[0][i].getUConst() == unionArrays[1][i].getUConst());
1860 break;
1861 case EbtBool:
1862 tempConstArray[i].setBConst(unionArrays[0][i].getBConst() == unionArrays[1][i].getBConst());
1863 break;
1864 default:
1865 UNREACHABLE();
1866 break;
1867 }
1868 }
1869 }
1870 break;
1871
1872 case EOpVectorNotEqual:
1873 {
1874 tempConstArray = new TConstantUnion[maxObjectSize];
1875 for (size_t i = 0; i < maxObjectSize; i++)
1876 {
1877 switch (basicType)
1878 {
1879 case EbtFloat:
1880 tempConstArray[i].setBConst(unionArrays[0][i].getFConst() != unionArrays[1][i].getFConst());
1881 break;
1882 case EbtInt:
1883 tempConstArray[i].setBConst(unionArrays[0][i].getIConst() != unionArrays[1][i].getIConst());
1884 break;
1885 case EbtUInt:
1886 tempConstArray[i].setBConst(unionArrays[0][i].getUConst() != unionArrays[1][i].getUConst());
1887 break;
1888 case EbtBool:
1889 tempConstArray[i].setBConst(unionArrays[0][i].getBConst() != unionArrays[1][i].getBConst());
1890 break;
1891 default:
1892 UNREACHABLE();
1893 break;
1894 }
1895 }
1896 }
1897 break;
1898
Arun Patole1155ddd2015-06-05 18:04:36 +05301899 case EOpDistance:
1900 if (basicType == EbtFloat)
1901 {
1902 TConstantUnion *distanceArray = new TConstantUnion[maxObjectSize];
1903 tempConstArray = new TConstantUnion();
1904 for (size_t i = 0; i < maxObjectSize; i++)
1905 {
1906 float x = unionArrays[0][i].getFConst();
1907 float y = unionArrays[1][i].getFConst();
1908 distanceArray[i].setFConst(x - y);
1909 }
1910 tempConstArray->setFConst(VectorLength(distanceArray, maxObjectSize));
1911 }
1912 else
1913 UNREACHABLE();
1914 break;
1915
1916 case EOpDot:
1917 if (basicType == EbtFloat)
1918 {
1919 tempConstArray = new TConstantUnion();
1920 tempConstArray->setFConst(VectorDotProduct(unionArrays[0], unionArrays[1], maxObjectSize));
1921 }
1922 else
1923 UNREACHABLE();
1924 break;
1925
1926 case EOpCross:
1927 if (basicType == EbtFloat && maxObjectSize == 3)
1928 {
1929 tempConstArray = new TConstantUnion[maxObjectSize];
1930 float x0 = unionArrays[0][0].getFConst();
1931 float x1 = unionArrays[0][1].getFConst();
1932 float x2 = unionArrays[0][2].getFConst();
1933 float y0 = unionArrays[1][0].getFConst();
1934 float y1 = unionArrays[1][1].getFConst();
1935 float y2 = unionArrays[1][2].getFConst();
1936 tempConstArray[0].setFConst(x1 * y2 - y1 * x2);
1937 tempConstArray[1].setFConst(x2 * y0 - y2 * x0);
1938 tempConstArray[2].setFConst(x0 * y1 - y0 * x1);
1939 }
1940 else
1941 UNREACHABLE();
1942 break;
1943
1944 case EOpReflect:
1945 if (basicType == EbtFloat)
1946 {
1947 // genType reflect (genType I, genType N) :
1948 // For the incident vector I and surface orientation N, returns the reflection direction:
1949 // I - 2 * dot(N, I) * N.
1950 tempConstArray = new TConstantUnion[maxObjectSize];
1951 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
1952 for (size_t i = 0; i < maxObjectSize; i++)
1953 {
1954 float result = unionArrays[0][i].getFConst() -
1955 2.0f * dotProduct * unionArrays[1][i].getFConst();
1956 tempConstArray[i].setFConst(result);
1957 }
1958 }
1959 else
1960 UNREACHABLE();
1961 break;
1962
Arun Patole274f0702015-05-05 13:33:30 +05301963 default:
1964 UNREACHABLE();
1965 // TODO: Add constant folding support for other built-in operations that take 2 parameters and not handled above.
1966 return nullptr;
1967 }
1968 }
1969 else if (paramsCount == 3)
1970 {
1971 //
1972 // Ternary built-in
1973 //
1974 switch (op)
1975 {
1976 case EOpClamp:
1977 {
1978 tempConstArray = new TConstantUnion[maxObjectSize];
1979 for (size_t i = 0; i < maxObjectSize; i++)
1980 {
1981 switch (basicType)
1982 {
1983 case EbtFloat:
1984 {
1985 float x = unionArrays[0][i].getFConst();
1986 float min = unionArrays[1][i].getFConst();
1987 float max = unionArrays[2][i].getFConst();
1988 // Results are undefined if min > max.
1989 if (min > max)
Arun Patole081c3f22015-05-25 15:43:35 +05301990 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &tempConstArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05301991 else
1992 tempConstArray[i].setFConst(gl::clamp(x, min, max));
1993 }
1994 break;
1995 case EbtInt:
1996 {
1997 int x = unionArrays[0][i].getIConst();
1998 int min = unionArrays[1][i].getIConst();
1999 int max = unionArrays[2][i].getIConst();
2000 // Results are undefined if min > max.
2001 if (min > max)
Arun Patole081c3f22015-05-25 15:43:35 +05302002 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &tempConstArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302003 else
2004 tempConstArray[i].setIConst(gl::clamp(x, min, max));
2005 }
2006 break;
2007 case EbtUInt:
2008 {
2009 unsigned int x = unionArrays[0][i].getUConst();
2010 unsigned int min = unionArrays[1][i].getUConst();
2011 unsigned int max = unionArrays[2][i].getUConst();
2012 // Results are undefined if min > max.
2013 if (min > max)
Arun Patole081c3f22015-05-25 15:43:35 +05302014 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &tempConstArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302015 else
2016 tempConstArray[i].setUConst(gl::clamp(x, min, max));
2017 }
2018 break;
2019 default:
2020 UNREACHABLE();
2021 break;
2022 }
2023 }
2024 }
2025 break;
2026
Arun Patolebf790422015-05-18 17:53:04 +05302027 case EOpMix:
2028 {
2029 if (basicType == EbtFloat)
2030 {
2031 tempConstArray = new TConstantUnion[maxObjectSize];
2032 for (size_t i = 0; i < maxObjectSize; i++)
2033 {
2034 float x = unionArrays[0][i].getFConst();
2035 float y = unionArrays[1][i].getFConst();
2036 TBasicType type = (*sequence)[2]->getAsTyped()->getType().getBasicType();
2037 if (type == EbtFloat)
2038 {
2039 // Returns the linear blend of x and y, i.e., x * (1 - a) + y * a.
2040 float a = unionArrays[2][i].getFConst();
2041 tempConstArray[i].setFConst(x * (1.0f - a) + y * a);
2042 }
2043 else // 3rd parameter is EbtBool
2044 {
2045 ASSERT(type == EbtBool);
2046 // Selects which vector each returned component comes from.
2047 // For a component of a that is false, the corresponding component of x is returned.
2048 // For a component of a that is true, the corresponding component of y is returned.
2049 bool a = unionArrays[2][i].getBConst();
2050 tempConstArray[i].setFConst(a ? y : x);
2051 }
2052 }
2053 }
2054 else
2055 UNREACHABLE();
2056 }
2057 break;
2058
2059 case EOpSmoothStep:
2060 {
2061 if (basicType == EbtFloat)
2062 {
2063 tempConstArray = new TConstantUnion[maxObjectSize];
2064 for (size_t i = 0; i < maxObjectSize; i++)
2065 {
2066 float edge0 = unionArrays[0][i].getFConst();
2067 float edge1 = unionArrays[1][i].getFConst();
2068 float x = unionArrays[2][i].getFConst();
2069 // Results are undefined if edge0 >= edge1.
2070 if (edge0 >= edge1)
2071 {
2072 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &tempConstArray[i]);
2073 }
2074 else
2075 {
2076 // Returns 0.0 if x <= edge0 and 1.0 if x >= edge1 and performs smooth
2077 // Hermite interpolation between 0 and 1 when edge0 < x < edge1.
2078 float t = gl::clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f);
2079 tempConstArray[i].setFConst(t * t * (3.0f - 2.0f * t));
2080 }
2081 }
2082 }
2083 else
2084 UNREACHABLE();
2085 }
2086 break;
2087
Arun Patole1155ddd2015-06-05 18:04:36 +05302088 case EOpFaceForward:
2089 if (basicType == EbtFloat)
2090 {
2091 // genType faceforward(genType N, genType I, genType Nref) :
2092 // If dot(Nref, I) < 0 return N, otherwise return -N.
2093 tempConstArray = new TConstantUnion[maxObjectSize];
2094 float dotProduct = VectorDotProduct(unionArrays[2], unionArrays[1], maxObjectSize);
2095 for (size_t i = 0; i < maxObjectSize; i++)
2096 {
2097 if (dotProduct < 0)
2098 tempConstArray[i].setFConst(unionArrays[0][i].getFConst());
2099 else
2100 tempConstArray[i].setFConst(-unionArrays[0][i].getFConst());
2101 }
2102 }
2103 else
2104 UNREACHABLE();
2105 break;
2106
2107 case EOpRefract:
2108 if (basicType == EbtFloat)
2109 {
2110 // genType refract(genType I, genType N, float eta) :
2111 // For the incident vector I and surface normal N, and the ratio of indices of refraction eta,
2112 // return the refraction vector. The result is computed by
2113 // k = 1.0 - eta * eta * (1.0 - dot(N, I) * dot(N, I))
2114 // if (k < 0.0)
2115 // return genType(0.0)
2116 // else
2117 // return eta * I - (eta * dot(N, I) + sqrt(k)) * N
2118 tempConstArray = new TConstantUnion[maxObjectSize];
2119 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
2120 for (size_t i = 0; i < maxObjectSize; i++)
2121 {
2122 float eta = unionArrays[2][i].getFConst();
2123 float k = 1.0f - eta * eta * (1.0f - dotProduct * dotProduct);
2124 if (k < 0.0f)
2125 tempConstArray[i].setFConst(0.0f);
2126 else
2127 tempConstArray[i].setFConst(eta * unionArrays[0][i].getFConst() -
2128 (eta * dotProduct + sqrtf(k)) * unionArrays[1][i].getFConst());
2129 }
2130 }
2131 else
2132 UNREACHABLE();
2133 break;
2134
Arun Patole274f0702015-05-05 13:33:30 +05302135 default:
2136 UNREACHABLE();
2137 // TODO: Add constant folding support for other built-in operations that take 3 parameters and not handled above.
2138 return nullptr;
2139 }
2140 }
2141
2142 if (tempConstArray)
2143 {
2144 tempNode = new TIntermConstantUnion(tempConstArray, returnType);
2145 tempNode->setLine(loc);
2146 }
2147 return tempNode;
2148}
2149
2150// static
Jamie Madillb1a85f42014-08-19 15:23:24 -04002151TString TIntermTraverser::hash(const TString &name, ShHashFunction64 hashFunction)
2152{
2153 if (hashFunction == NULL || name.empty())
2154 return name;
2155 khronos_uint64_t number = (*hashFunction)(name.c_str(), name.length());
2156 TStringStream stream;
2157 stream << HASHED_NAME_PREFIX << std::hex << number;
2158 TString hashedName = stream.str();
2159 return hashedName;
2160}
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002161
2162void TIntermTraverser::updateTree()
2163{
Olli Etuahoa6f22092015-05-08 18:31:10 +03002164 for (size_t ii = 0; ii < mInsertions.size(); ++ii)
2165 {
2166 const NodeInsertMultipleEntry &insertion = mInsertions[ii];
2167 ASSERT(insertion.parent);
2168 bool inserted = insertion.parent->insertChildNodes(insertion.position, insertion.insertions);
2169 ASSERT(inserted);
2170 UNUSED_ASSERTION_VARIABLE(inserted);
2171 }
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002172 for (size_t ii = 0; ii < mReplacements.size(); ++ii)
2173 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03002174 const NodeUpdateEntry &replacement = mReplacements[ii];
2175 ASSERT(replacement.parent);
2176 bool replaced = replacement.parent->replaceChildNode(
2177 replacement.original, replacement.replacement);
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002178 ASSERT(replaced);
Olli Etuahod57e0db2015-04-24 15:05:08 +03002179 UNUSED_ASSERTION_VARIABLE(replaced);
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002180
Olli Etuahocd94ef92015-04-16 19:18:10 +03002181 if (!replacement.originalBecomesChildOfReplacement)
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002182 {
2183 // In AST traversing, a parent is visited before its children.
Olli Etuahocd94ef92015-04-16 19:18:10 +03002184 // After we replace a node, if its immediate child is to
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002185 // be replaced, we need to make sure we don't update the replaced
2186 // node; instead, we update the replacement node.
2187 for (size_t jj = ii + 1; jj < mReplacements.size(); ++jj)
2188 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03002189 NodeUpdateEntry &replacement2 = mReplacements[jj];
2190 if (replacement2.parent == replacement.original)
2191 replacement2.parent = replacement.replacement;
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002192 }
2193 }
2194 }
Olli Etuahofc0e2bc2015-04-16 13:39:56 +03002195 for (size_t ii = 0; ii < mMultiReplacements.size(); ++ii)
2196 {
2197 const NodeReplaceWithMultipleEntry &replacement = mMultiReplacements[ii];
2198 ASSERT(replacement.parent);
2199 bool replaced = replacement.parent->replaceChildNodeWithMultiple(
2200 replacement.original, replacement.replacements);
2201 ASSERT(replaced);
Olli Etuahod57e0db2015-04-24 15:05:08 +03002202 UNUSED_ASSERTION_VARIABLE(replaced);
Olli Etuahofc0e2bc2015-04-16 13:39:56 +03002203 }
Olli Etuahod4f303e2015-05-20 17:09:06 +03002204
2205 mInsertions.clear();
2206 mReplacements.clear();
2207 mMultiReplacements.clear();
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002208}