blob: 5aed4f8eea8c007f7c005ea17571163a31c2e9a9 [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
750//
751// The fold functions see if an operation on a constant can be done in place,
752// without generating run-time code.
753//
Jamie Madillaebd0022015-06-04 19:43:44 +0000754// Returns the node to keep using, which may or may not be the node passed in.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400755//
Jamie Madillaebd0022015-06-04 19:43:44 +0000756TIntermTyped *TIntermConstantUnion::fold(
757 TOperator op, TIntermConstantUnion *rightNode, TInfoSink &infoSink)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400758{
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400759 TConstantUnion *unionArray = getUnionArrayPointer();
Jamie Madillb1a85f42014-08-19 15:23:24 -0400760
761 if (!unionArray)
Arun Patolefddc2112015-04-22 13:28:10 +0530762 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400763
764 size_t objectSize = getType().getObjectSize();
765
Jamie Madillaebd0022015-06-04 19:43:44 +0000766 if (rightNode)
767 {
768 // binary operations
769 TConstantUnion *rightUnionArray = rightNode->getUnionArrayPointer();
770 TType returnType = getType();
771
772 if (!rightUnionArray)
773 return nullptr;
774
775 // for a case like float f = vec4(2, 3, 4, 5) + 1.2;
776 if (rightNode->getType().getObjectSize() == 1 && objectSize > 1)
777 {
778 rightUnionArray = Vectorize(*rightNode->getUnionArrayPointer(), objectSize);
779 returnType = getType();
780 }
781 else if (rightNode->getType().getObjectSize() > 1 && objectSize == 1)
782 {
783 // for a case like float f = 1.2 + vec4(2, 3, 4, 5);
784 unionArray = Vectorize(*getUnionArrayPointer(), rightNode->getType().getObjectSize());
785 returnType = rightNode->getType();
786 objectSize = rightNode->getType().getObjectSize();
787 }
788
789 TConstantUnion *tempConstArray = nullptr;
790 TIntermConstantUnion *tempNode;
791
792 bool boolNodeFlag = false;
793 switch(op)
794 {
795 case EOpAdd:
796 tempConstArray = new TConstantUnion[objectSize];
797 for (size_t i = 0; i < objectSize; i++)
798 tempConstArray[i] = unionArray[i] + rightUnionArray[i];
799 break;
800 case EOpSub:
801 tempConstArray = new TConstantUnion[objectSize];
802 for (size_t i = 0; i < objectSize; i++)
803 tempConstArray[i] = unionArray[i] - rightUnionArray[i];
804 break;
805
806 case EOpMul:
807 case EOpVectorTimesScalar:
808 case EOpMatrixTimesScalar:
809 tempConstArray = new TConstantUnion[objectSize];
810 for (size_t i = 0; i < objectSize; i++)
811 tempConstArray[i] = unionArray[i] * rightUnionArray[i];
812 break;
813
814 case EOpMatrixTimesMatrix:
815 {
816 if (getType().getBasicType() != EbtFloat ||
817 rightNode->getBasicType() != EbtFloat)
818 {
819 infoSink.info.message(
820 EPrefixInternalError, getLine(),
821 "Constant Folding cannot be done for matrix multiply");
822 return nullptr;
823 }
824
825 const int leftCols = getCols();
826 const int leftRows = getRows();
827 const int rightCols = rightNode->getType().getCols();
828 const int rightRows = rightNode->getType().getRows();
829 const int resultCols = rightCols;
830 const int resultRows = leftRows;
831
832 tempConstArray = new TConstantUnion[resultCols * resultRows];
833 for (int row = 0; row < resultRows; row++)
834 {
835 for (int column = 0; column < resultCols; column++)
836 {
837 tempConstArray[resultRows * column + row].setFConst(0.0f);
838 for (int i = 0; i < leftCols; i++)
839 {
840 tempConstArray[resultRows * column + row].setFConst(
841 tempConstArray[resultRows * column + row].getFConst() +
842 unionArray[i * leftRows + row].getFConst() *
843 rightUnionArray[column * rightRows + i].getFConst());
844 }
845 }
846 }
847
848 // update return type for matrix product
849 returnType.setPrimarySize(static_cast<unsigned char>(resultCols));
850 returnType.setSecondarySize(static_cast<unsigned char>(resultRows));
851 }
852 break;
853
854 case EOpDiv:
855 case EOpIMod:
856 {
857 tempConstArray = new TConstantUnion[objectSize];
858 for (size_t i = 0; i < objectSize; i++)
859 {
860 switch (getType().getBasicType())
861 {
862 case EbtFloat:
863 if (rightUnionArray[i] == 0.0f)
864 {
865 infoSink.info.message(
866 EPrefixWarning, getLine(),
867 "Divide by zero error during constant folding");
868 tempConstArray[i].setFConst(
869 unionArray[i].getFConst() < 0 ? -FLT_MAX : FLT_MAX);
870 }
871 else
872 {
873 ASSERT(op == EOpDiv);
874 tempConstArray[i].setFConst(
875 unionArray[i].getFConst() /
876 rightUnionArray[i].getFConst());
877 }
878 break;
879
880 case EbtInt:
881 if (rightUnionArray[i] == 0)
882 {
883 infoSink.info.message(
884 EPrefixWarning, getLine(),
885 "Divide by zero error during constant folding");
886 tempConstArray[i].setIConst(INT_MAX);
887 }
888 else
889 {
890 if (op == EOpDiv)
891 {
892 tempConstArray[i].setIConst(
893 unionArray[i].getIConst() /
894 rightUnionArray[i].getIConst());
895 }
896 else
897 {
898 ASSERT(op == EOpIMod);
899 tempConstArray[i].setIConst(
900 unionArray[i].getIConst() %
901 rightUnionArray[i].getIConst());
902 }
903 }
904 break;
905
906 case EbtUInt:
907 if (rightUnionArray[i] == 0)
908 {
909 infoSink.info.message(
910 EPrefixWarning, getLine(),
911 "Divide by zero error during constant folding");
912 tempConstArray[i].setUConst(UINT_MAX);
913 }
914 else
915 {
916 if (op == EOpDiv)
917 {
918 tempConstArray[i].setUConst(
919 unionArray[i].getUConst() /
920 rightUnionArray[i].getUConst());
921 }
922 else
923 {
924 ASSERT(op == EOpIMod);
925 tempConstArray[i].setUConst(
926 unionArray[i].getUConst() %
927 rightUnionArray[i].getUConst());
928 }
929 }
930 break;
931
932 default:
933 infoSink.info.message(
934 EPrefixInternalError, getLine(),
935 "Constant folding cannot be done for \"/\"");
936 return nullptr;
937 }
938 }
939 }
940 break;
941
942 case EOpMatrixTimesVector:
943 {
944 if (rightNode->getBasicType() != EbtFloat)
945 {
946 infoSink.info.message(
947 EPrefixInternalError, getLine(),
948 "Constant Folding cannot be done for matrix times vector");
949 return nullptr;
950 }
951
952 const int matrixCols = getCols();
953 const int matrixRows = getRows();
954
955 tempConstArray = new TConstantUnion[matrixRows];
956
957 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
958 {
959 tempConstArray[matrixRow].setFConst(0.0f);
960 for (int col = 0; col < matrixCols; col++)
961 {
962 tempConstArray[matrixRow].setFConst(
963 tempConstArray[matrixRow].getFConst() +
964 unionArray[col * matrixRows + matrixRow].getFConst() *
965 rightUnionArray[col].getFConst());
966 }
967 }
968
969 returnType = rightNode->getType();
970 returnType.setPrimarySize(static_cast<unsigned char>(matrixRows));
971
972 tempNode = new TIntermConstantUnion(tempConstArray, returnType);
973 tempNode->setLine(getLine());
974
975 return tempNode;
976 }
977
978 case EOpVectorTimesMatrix:
979 {
980 if (getType().getBasicType() != EbtFloat)
981 {
982 infoSink.info.message(
983 EPrefixInternalError, getLine(),
984 "Constant Folding cannot be done for vector times matrix");
985 return nullptr;
986 }
987
988 const int matrixCols = rightNode->getType().getCols();
989 const int matrixRows = rightNode->getType().getRows();
990
991 tempConstArray = new TConstantUnion[matrixCols];
992
993 for (int matrixCol = 0; matrixCol < matrixCols; matrixCol++)
994 {
995 tempConstArray[matrixCol].setFConst(0.0f);
996 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
997 {
998 tempConstArray[matrixCol].setFConst(
999 tempConstArray[matrixCol].getFConst() +
1000 unionArray[matrixRow].getFConst() *
1001 rightUnionArray[matrixCol * matrixRows + matrixRow].getFConst());
1002 }
1003 }
1004
1005 returnType.setPrimarySize(static_cast<unsigned char>(matrixCols));
1006 }
1007 break;
1008
1009 case EOpLogicalAnd:
1010 // this code is written for possible future use,
1011 // will not get executed currently
1012 {
1013 tempConstArray = new TConstantUnion[objectSize];
1014 for (size_t i = 0; i < objectSize; i++)
1015 {
1016 tempConstArray[i] = unionArray[i] && rightUnionArray[i];
1017 }
1018 }
1019 break;
1020
1021 case EOpLogicalOr:
1022 // this code is written for possible future use,
1023 // will not get executed currently
1024 {
1025 tempConstArray = new TConstantUnion[objectSize];
1026 for (size_t i = 0; i < objectSize; i++)
1027 {
1028 tempConstArray[i] = unionArray[i] || rightUnionArray[i];
1029 }
1030 }
1031 break;
1032
1033 case EOpLogicalXor:
1034 {
1035 tempConstArray = new TConstantUnion[objectSize];
1036 for (size_t i = 0; i < objectSize; i++)
1037 {
1038 switch (getType().getBasicType())
1039 {
1040 case EbtBool:
1041 tempConstArray[i].setBConst(
1042 unionArray[i] == rightUnionArray[i] ? false : true);
1043 break;
1044 default:
1045 UNREACHABLE();
1046 break;
1047 }
1048 }
1049 }
1050 break;
1051
1052 case EOpBitwiseAnd:
1053 tempConstArray = new TConstantUnion[objectSize];
1054 for (size_t i = 0; i < objectSize; i++)
1055 tempConstArray[i] = unionArray[i] & rightUnionArray[i];
1056 break;
1057 case EOpBitwiseXor:
1058 tempConstArray = new TConstantUnion[objectSize];
1059 for (size_t i = 0; i < objectSize; i++)
1060 tempConstArray[i] = unionArray[i] ^ rightUnionArray[i];
1061 break;
1062 case EOpBitwiseOr:
1063 tempConstArray = new TConstantUnion[objectSize];
1064 for (size_t i = 0; i < objectSize; i++)
1065 tempConstArray[i] = unionArray[i] | rightUnionArray[i];
1066 break;
1067 case EOpBitShiftLeft:
1068 tempConstArray = new TConstantUnion[objectSize];
1069 for (size_t i = 0; i < objectSize; i++)
1070 tempConstArray[i] = unionArray[i] << rightUnionArray[i];
1071 break;
1072 case EOpBitShiftRight:
1073 tempConstArray = new TConstantUnion[objectSize];
1074 for (size_t i = 0; i < objectSize; i++)
1075 tempConstArray[i] = unionArray[i] >> rightUnionArray[i];
1076 break;
1077
1078 case EOpLessThan:
1079 ASSERT(objectSize == 1);
1080 tempConstArray = new TConstantUnion[1];
1081 tempConstArray->setBConst(*unionArray < *rightUnionArray);
1082 returnType = TType(EbtBool, EbpUndefined, EvqConst);
1083 break;
1084
1085 case EOpGreaterThan:
1086 ASSERT(objectSize == 1);
1087 tempConstArray = new TConstantUnion[1];
1088 tempConstArray->setBConst(*unionArray > *rightUnionArray);
1089 returnType = TType(EbtBool, EbpUndefined, EvqConst);
1090 break;
1091
1092 case EOpLessThanEqual:
1093 {
1094 ASSERT(objectSize == 1);
1095 TConstantUnion constant;
1096 constant.setBConst(*unionArray > *rightUnionArray);
1097 tempConstArray = new TConstantUnion[1];
1098 tempConstArray->setBConst(!constant.getBConst());
1099 returnType = TType(EbtBool, EbpUndefined, EvqConst);
1100 break;
1101 }
1102
1103 case EOpGreaterThanEqual:
1104 {
1105 ASSERT(objectSize == 1);
1106 TConstantUnion constant;
1107 constant.setBConst(*unionArray < *rightUnionArray);
1108 tempConstArray = new TConstantUnion[1];
1109 tempConstArray->setBConst(!constant.getBConst());
1110 returnType = TType(EbtBool, EbpUndefined, EvqConst);
1111 break;
1112 }
1113
1114 case EOpEqual:
1115 if (getType().getBasicType() == EbtStruct)
1116 {
1117 if (!CompareStructure(rightNode->getType(),
1118 rightNode->getUnionArrayPointer(),
1119 unionArray))
1120 {
1121 boolNodeFlag = true;
1122 }
1123 }
1124 else
1125 {
1126 for (size_t i = 0; i < objectSize; i++)
1127 {
1128 if (unionArray[i] != rightUnionArray[i])
1129 {
1130 boolNodeFlag = true;
1131 break; // break out of for loop
1132 }
1133 }
1134 }
1135
1136 tempConstArray = new TConstantUnion[1];
1137 if (!boolNodeFlag)
1138 {
1139 tempConstArray->setBConst(true);
1140 }
1141 else
1142 {
1143 tempConstArray->setBConst(false);
1144 }
1145
1146 tempNode = new TIntermConstantUnion(
1147 tempConstArray, TType(EbtBool, EbpUndefined, EvqConst));
1148 tempNode->setLine(getLine());
1149
1150 return tempNode;
1151
1152 case EOpNotEqual:
1153 if (getType().getBasicType() == EbtStruct)
1154 {
1155 if (CompareStructure(rightNode->getType(),
1156 rightNode->getUnionArrayPointer(),
1157 unionArray))
1158 {
1159 boolNodeFlag = true;
1160 }
1161 }
1162 else
1163 {
1164 for (size_t i = 0; i < objectSize; i++)
1165 {
1166 if (unionArray[i] == rightUnionArray[i])
1167 {
1168 boolNodeFlag = true;
1169 break; // break out of for loop
1170 }
1171 }
1172 }
1173
1174 tempConstArray = new TConstantUnion[1];
1175 if (!boolNodeFlag)
1176 {
1177 tempConstArray->setBConst(true);
1178 }
1179 else
1180 {
1181 tempConstArray->setBConst(false);
1182 }
1183
1184 tempNode = new TIntermConstantUnion(
1185 tempConstArray, TType(EbtBool, EbpUndefined, EvqConst));
1186 tempNode->setLine(getLine());
1187
1188 return tempNode;
1189
1190 default:
1191 infoSink.info.message(
1192 EPrefixInternalError, getLine(),
1193 "Invalid operator for constant folding");
1194 return nullptr;
1195 }
1196 tempNode = new TIntermConstantUnion(tempConstArray, returnType);
1197 tempNode->setLine(getLine());
1198
1199 return tempNode;
1200 }
Arun Patole1155ddd2015-06-05 18:04:36 +05301201 else if (op == EOpAny || op == EOpAll || op == EOpLength)
Arun Patole9d0b1f92015-05-20 14:27:17 +05301202 {
1203 // Do operations where the return type is different from the operand type.
1204
Arun Patole1155ddd2015-06-05 18:04:36 +05301205 TType returnType;
Arun Patole9d0b1f92015-05-20 14:27:17 +05301206 TConstantUnion *tempConstArray = nullptr;
Arun Patole1155ddd2015-06-05 18:04:36 +05301207 switch (op)
Arun Patole9d0b1f92015-05-20 14:27:17 +05301208 {
Arun Patole1155ddd2015-06-05 18:04:36 +05301209 case EOpAny:
Arun Patole9d0b1f92015-05-20 14:27:17 +05301210 if (getType().getBasicType() == EbtBool)
1211 {
1212 tempConstArray = new TConstantUnion();
1213 tempConstArray->setBConst(false);
1214 for (size_t i = 0; i < objectSize; i++)
1215 {
1216 if (unionArray[i].getBConst())
1217 {
1218 tempConstArray->setBConst(true);
1219 break;
1220 }
1221 }
Arun Patole1155ddd2015-06-05 18:04:36 +05301222 returnType = TType(EbtBool, EbpUndefined, EvqConst);
1223 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05301224 }
1225 else
1226 {
Arun Patole1155ddd2015-06-05 18:04:36 +05301227 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
Arun Patole9d0b1f92015-05-20 14:27:17 +05301228 return nullptr;
1229 }
Arun Patole1155ddd2015-06-05 18:04:36 +05301230
1231 case EOpAll:
Arun Patole9d0b1f92015-05-20 14:27:17 +05301232 if (getType().getBasicType() == EbtBool)
1233 {
1234 tempConstArray = new TConstantUnion();
1235 tempConstArray->setBConst(true);
1236 for (size_t i = 0; i < objectSize; i++)
1237 {
1238 if (!unionArray[i].getBConst())
1239 {
1240 tempConstArray->setBConst(false);
1241 break;
1242 }
1243 }
Arun Patole1155ddd2015-06-05 18:04:36 +05301244 returnType = TType(EbtBool, EbpUndefined, EvqConst);
1245 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05301246 }
1247 else
1248 {
Arun Patole1155ddd2015-06-05 18:04:36 +05301249 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
Arun Patole9d0b1f92015-05-20 14:27:17 +05301250 return nullptr;
1251 }
Arun Patole1155ddd2015-06-05 18:04:36 +05301252
1253 case EOpLength:
1254 if (getType().getBasicType() == EbtFloat)
1255 {
1256 tempConstArray = new TConstantUnion();
1257 tempConstArray->setFConst(VectorLength(unionArray, objectSize));
1258 returnType = TType(EbtFloat, getType().getPrecision(), EvqConst);
1259 break;
1260 }
1261 else
1262 {
1263 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1264 return nullptr;
1265 }
1266
1267 default:
1268 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05301269 }
Arun Patole1155ddd2015-06-05 18:04:36 +05301270
Arun Patole9d0b1f92015-05-20 14:27:17 +05301271 TIntermConstantUnion *tempNode = new TIntermConstantUnion(tempConstArray, returnType);
1272 tempNode->setLine(getLine());
1273 return tempNode;
1274 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04001275 else
1276 {
1277 //
Arun Patole9d0b1f92015-05-20 14:27:17 +05301278 // Do unary operations where the return type is the same as operand type.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001279 //
1280 TIntermConstantUnion *newNode = 0;
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001281 TConstantUnion* tempConstArray = new TConstantUnion[objectSize];
Jamie Madillb1a85f42014-08-19 15:23:24 -04001282 for (size_t i = 0; i < objectSize; i++)
1283 {
1284 switch(op)
1285 {
1286 case EOpNegative:
1287 switch (getType().getBasicType())
1288 {
1289 case EbtFloat:
1290 tempConstArray[i].setFConst(-unionArray[i].getFConst());
1291 break;
1292 case EbtInt:
1293 tempConstArray[i].setIConst(-unionArray[i].getIConst());
1294 break;
1295 case EbtUInt:
1296 tempConstArray[i].setUConst(static_cast<unsigned int>(
1297 -static_cast<int>(unionArray[i].getUConst())));
1298 break;
1299 default:
1300 infoSink.info.message(
1301 EPrefixInternalError, getLine(),
1302 "Unary operation not folded into constant");
Arun Patolefddc2112015-04-22 13:28:10 +05301303 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001304 }
1305 break;
1306
Zhenyao Mode1e00e2014-10-09 16:55:32 -07001307 case EOpPositive:
1308 switch (getType().getBasicType())
1309 {
1310 case EbtFloat:
1311 tempConstArray[i].setFConst(unionArray[i].getFConst());
1312 break;
1313 case EbtInt:
1314 tempConstArray[i].setIConst(unionArray[i].getIConst());
1315 break;
1316 case EbtUInt:
1317 tempConstArray[i].setUConst(static_cast<unsigned int>(
1318 static_cast<int>(unionArray[i].getUConst())));
1319 break;
1320 default:
1321 infoSink.info.message(
1322 EPrefixInternalError, getLine(),
1323 "Unary operation not folded into constant");
Arun Patolefddc2112015-04-22 13:28:10 +05301324 return nullptr;
Zhenyao Mode1e00e2014-10-09 16:55:32 -07001325 }
1326 break;
1327
Jamie Madillb1a85f42014-08-19 15:23:24 -04001328 case EOpLogicalNot:
1329 // this code is written for possible future use,
1330 // will not get executed currently
1331 switch (getType().getBasicType())
1332 {
1333 case EbtBool:
1334 tempConstArray[i].setBConst(!unionArray[i].getBConst());
1335 break;
1336 default:
1337 infoSink.info.message(
1338 EPrefixInternalError, getLine(),
1339 "Unary operation not folded into constant");
Arun Patolefddc2112015-04-22 13:28:10 +05301340 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001341 }
1342 break;
1343
Olli Etuaho31b5fc62015-01-16 12:13:36 +02001344 case EOpBitwiseNot:
1345 switch (getType().getBasicType())
1346 {
1347 case EbtInt:
1348 tempConstArray[i].setIConst(~unionArray[i].getIConst());
1349 break;
1350 case EbtUInt:
1351 tempConstArray[i].setUConst(~unionArray[i].getUConst());
1352 break;
1353 default:
1354 infoSink.info.message(
1355 EPrefixInternalError, getLine(),
1356 "Unary operation not folded into constant");
Arun Patolefddc2112015-04-22 13:28:10 +05301357 return nullptr;
Olli Etuaho31b5fc62015-01-16 12:13:36 +02001358 }
1359 break;
1360
Arun Patole9dea48f2015-04-02 11:45:09 +05301361 case EOpRadians:
1362 if (getType().getBasicType() == EbtFloat)
1363 {
1364 tempConstArray[i].setFConst(kDegreesToRadiansMultiplier * unionArray[i].getFConst());
1365 break;
1366 }
1367 infoSink.info.message(
1368 EPrefixInternalError, getLine(),
1369 "Unary operation not folded into constant");
1370 return nullptr;
1371
1372 case EOpDegrees:
1373 if (getType().getBasicType() == EbtFloat)
1374 {
1375 tempConstArray[i].setFConst(kRadiansToDegreesMultiplier * unionArray[i].getFConst());
1376 break;
1377 }
1378 infoSink.info.message(
1379 EPrefixInternalError, getLine(),
1380 "Unary operation not folded into constant");
1381 return nullptr;
1382
1383 case EOpSin:
1384 if (!foldFloatTypeUnary(unionArray[i], &sinf, infoSink, &tempConstArray[i]))
1385 return nullptr;
1386 break;
1387
1388 case EOpCos:
1389 if (!foldFloatTypeUnary(unionArray[i], &cosf, infoSink, &tempConstArray[i]))
1390 return nullptr;
1391 break;
1392
1393 case EOpTan:
1394 if (!foldFloatTypeUnary(unionArray[i], &tanf, infoSink, &tempConstArray[i]))
1395 return nullptr;
1396 break;
1397
1398 case EOpAsin:
1399 // For asin(x), results are undefined if |x| > 1, we are choosing to set result to 0.
1400 if (getType().getBasicType() == EbtFloat && fabsf(unionArray[i].getFConst()) > 1.0f)
Arun Patole081c3f22015-05-25 15:43:35 +05301401 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &tempConstArray[i]);
Arun Patole9dea48f2015-04-02 11:45:09 +05301402 else if (!foldFloatTypeUnary(unionArray[i], &asinf, infoSink, &tempConstArray[i]))
1403 return nullptr;
1404 break;
1405
1406 case EOpAcos:
1407 // For acos(x), results are undefined if |x| > 1, we are choosing to set result to 0.
1408 if (getType().getBasicType() == EbtFloat && fabsf(unionArray[i].getFConst()) > 1.0f)
Arun Patole081c3f22015-05-25 15:43:35 +05301409 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &tempConstArray[i]);
Arun Patole9dea48f2015-04-02 11:45:09 +05301410 else if (!foldFloatTypeUnary(unionArray[i], &acosf, infoSink, &tempConstArray[i]))
1411 return nullptr;
1412 break;
1413
1414 case EOpAtan:
1415 if (!foldFloatTypeUnary(unionArray[i], &atanf, infoSink, &tempConstArray[i]))
1416 return nullptr;
1417 break;
1418
1419 case EOpSinh:
1420 if (!foldFloatTypeUnary(unionArray[i], &sinhf, infoSink, &tempConstArray[i]))
1421 return nullptr;
1422 break;
1423
1424 case EOpCosh:
1425 if (!foldFloatTypeUnary(unionArray[i], &coshf, infoSink, &tempConstArray[i]))
1426 return nullptr;
1427 break;
1428
1429 case EOpTanh:
1430 if (!foldFloatTypeUnary(unionArray[i], &tanhf, infoSink, &tempConstArray[i]))
1431 return nullptr;
1432 break;
1433
1434 case EOpAsinh:
1435 if (!foldFloatTypeUnary(unionArray[i], &asinhf, infoSink, &tempConstArray[i]))
1436 return nullptr;
1437 break;
1438
1439 case EOpAcosh:
1440 // For acosh(x), results are undefined if x < 1, we are choosing to set result to 0.
1441 if (getType().getBasicType() == EbtFloat && unionArray[i].getFConst() < 1.0f)
Arun Patole081c3f22015-05-25 15:43:35 +05301442 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &tempConstArray[i]);
Arun Patole9dea48f2015-04-02 11:45:09 +05301443 else if (!foldFloatTypeUnary(unionArray[i], &acoshf, infoSink, &tempConstArray[i]))
1444 return nullptr;
1445 break;
1446
1447 case EOpAtanh:
1448 // For atanh(x), results are undefined if |x| >= 1, we are choosing to set result to 0.
1449 if (getType().getBasicType() == EbtFloat && fabsf(unionArray[i].getFConst()) >= 1.0f)
Arun Patole081c3f22015-05-25 15:43:35 +05301450 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &tempConstArray[i]);
Arun Patole9dea48f2015-04-02 11:45:09 +05301451 else if (!foldFloatTypeUnary(unionArray[i], &atanhf, infoSink, &tempConstArray[i]))
1452 return nullptr;
1453 break;
1454
Arun Patole97dc22e2015-04-06 17:35:38 +05301455 case EOpAbs:
1456 switch (getType().getBasicType())
1457 {
1458 case EbtFloat:
1459 tempConstArray[i].setFConst(fabsf(unionArray[i].getFConst()));
1460 break;
1461 case EbtInt:
1462 tempConstArray[i].setIConst(abs(unionArray[i].getIConst()));
1463 break;
1464 default:
1465 infoSink.info.message(
1466 EPrefixInternalError, getLine(),
1467 "Unary operation not folded into constant");
1468 return nullptr;
1469 }
1470 break;
1471
1472 case EOpSign:
1473 switch (getType().getBasicType())
1474 {
1475 case EbtFloat:
1476 {
1477 float fConst = unionArray[i].getFConst();
1478 float fResult = 0.0f;
1479 if (fConst > 0.0f)
1480 fResult = 1.0f;
1481 else if (fConst < 0.0f)
1482 fResult = -1.0f;
1483 tempConstArray[i].setFConst(fResult);
1484 }
1485 break;
1486 case EbtInt:
1487 {
1488 int iConst = unionArray[i].getIConst();
1489 int iResult = 0;
1490 if (iConst > 0)
1491 iResult = 1;
1492 else if (iConst < 0)
1493 iResult = -1;
1494 tempConstArray[i].setIConst(iResult);
1495 }
1496 break;
1497 default:
1498 infoSink.info.message(
1499 EPrefixInternalError, getLine(),
1500 "Unary operation not folded into constant");
1501 return nullptr;
1502 }
1503 break;
1504
1505 case EOpFloor:
1506 if (!foldFloatTypeUnary(unionArray[i], &floorf, infoSink, &tempConstArray[i]))
1507 return nullptr;
1508 break;
1509
1510 case EOpTrunc:
1511 if (!foldFloatTypeUnary(unionArray[i], &truncf, infoSink, &tempConstArray[i]))
1512 return nullptr;
1513 break;
1514
1515 case EOpRound:
1516 if (!foldFloatTypeUnary(unionArray[i], &roundf, infoSink, &tempConstArray[i]))
1517 return nullptr;
1518 break;
1519
1520 case EOpRoundEven:
1521 if (getType().getBasicType() == EbtFloat)
1522 {
1523 float x = unionArray[i].getFConst();
1524 float result;
1525 float fractPart = modff(x, &result);
1526 if (fabsf(fractPart) == 0.5f)
1527 result = 2.0f * roundf(x / 2.0f);
1528 else
1529 result = roundf(x);
1530 tempConstArray[i].setFConst(result);
1531 break;
1532 }
1533 infoSink.info.message(
1534 EPrefixInternalError, getLine(),
1535 "Unary operation not folded into constant");
1536 return nullptr;
1537
1538 case EOpCeil:
1539 if (!foldFloatTypeUnary(unionArray[i], &ceilf, infoSink, &tempConstArray[i]))
1540 return nullptr;
1541 break;
1542
1543 case EOpFract:
1544 if (getType().getBasicType() == EbtFloat)
1545 {
1546 float x = unionArray[i].getFConst();
1547 tempConstArray[i].setFConst(x - floorf(x));
1548 break;
1549 }
1550 infoSink.info.message(
1551 EPrefixInternalError, getLine(),
1552 "Unary operation not folded into constant");
1553 return nullptr;
1554
Arun Patole28eb65e2015-04-06 17:29:48 +05301555 case EOpExp:
1556 if (!foldFloatTypeUnary(unionArray[i], &expf, infoSink, &tempConstArray[i]))
1557 return nullptr;
1558 break;
1559
1560 case EOpLog:
1561 // For log(x), results are undefined if x <= 0, we are choosing to set result to 0.
1562 if (getType().getBasicType() == EbtFloat && unionArray[i].getFConst() <= 0.0f)
Arun Patole081c3f22015-05-25 15:43:35 +05301563 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &tempConstArray[i]);
Arun Patole28eb65e2015-04-06 17:29:48 +05301564 else if (!foldFloatTypeUnary(unionArray[i], &logf, infoSink, &tempConstArray[i]))
1565 return nullptr;
1566 break;
1567
1568 case EOpExp2:
1569 if (!foldFloatTypeUnary(unionArray[i], &exp2f, infoSink, &tempConstArray[i]))
1570 return nullptr;
1571 break;
1572
1573 case EOpLog2:
1574 // For log2(x), results are undefined if x <= 0, we are choosing to set result to 0.
1575 // And log2f is not available on some plarforms like old android, so just using log(x)/log(2) here.
1576 if (getType().getBasicType() == EbtFloat && unionArray[i].getFConst() <= 0.0f)
Arun Patole081c3f22015-05-25 15:43:35 +05301577 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &tempConstArray[i]);
Arun Patole28eb65e2015-04-06 17:29:48 +05301578 else if (!foldFloatTypeUnary(unionArray[i], &logf, infoSink, &tempConstArray[i]))
1579 return nullptr;
1580 else
1581 tempConstArray[i].setFConst(tempConstArray[i].getFConst() / logf(2.0f));
1582 break;
1583
1584 case EOpSqrt:
1585 // For sqrt(x), results are undefined if x < 0, we are choosing to set result to 0.
1586 if (getType().getBasicType() == EbtFloat && unionArray[i].getFConst() < 0.0f)
Arun Patole081c3f22015-05-25 15:43:35 +05301587 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &tempConstArray[i]);
Arun Patole28eb65e2015-04-06 17:29:48 +05301588 else if (!foldFloatTypeUnary(unionArray[i], &sqrtf, infoSink, &tempConstArray[i]))
1589 return nullptr;
1590 break;
1591
1592 case EOpInverseSqrt:
1593 // There is no stdlib built-in function equavalent for GLES built-in inversesqrt(),
1594 // so getting the square root first using builtin function sqrt() and then taking its inverse.
1595 // Also, for inversesqrt(x), results are undefined if x <= 0, we are choosing to set result to 0.
1596 if (getType().getBasicType() == EbtFloat && unionArray[i].getFConst() <= 0.0f)
Arun Patole081c3f22015-05-25 15:43:35 +05301597 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &tempConstArray[i]);
Arun Patole28eb65e2015-04-06 17:29:48 +05301598 else if (!foldFloatTypeUnary(unionArray[i], &sqrtf, infoSink, &tempConstArray[i]))
1599 return nullptr;
1600 else
1601 tempConstArray[i].setFConst(1.0f / tempConstArray[i].getFConst());
1602 break;
1603
Arun Patole9d0b1f92015-05-20 14:27:17 +05301604 case EOpVectorLogicalNot:
1605 if (getType().getBasicType() == EbtBool)
1606 {
1607 tempConstArray[i].setBConst(!unionArray[i].getBConst());
1608 break;
1609 }
1610 infoSink.info.message(
1611 EPrefixInternalError, getLine(),
1612 "Unary operation not folded into constant");
1613 return nullptr;
1614
Arun Patole1155ddd2015-06-05 18:04:36 +05301615 case EOpNormalize:
1616 if (getType().getBasicType() == EbtFloat)
1617 {
1618 float x = unionArray[i].getFConst();
1619 float length = VectorLength(unionArray, objectSize);
1620 if (length)
1621 tempConstArray[i].setFConst(x / length);
1622 else
1623 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &tempConstArray[i]);
1624 break;
1625 }
1626 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1627 return nullptr;
1628
Jamie Madillb1a85f42014-08-19 15:23:24 -04001629 default:
Arun Patolefddc2112015-04-22 13:28:10 +05301630 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001631 }
1632 }
1633 newNode = new TIntermConstantUnion(tempConstArray, getType());
1634 newNode->setLine(getLine());
1635 return newNode;
1636 }
1637}
1638
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001639bool TIntermConstantUnion::foldFloatTypeUnary(const TConstantUnion &parameter, FloatTypeUnaryFunc builtinFunc,
1640 TInfoSink &infoSink, TConstantUnion *result) const
Arun Patole9dea48f2015-04-02 11:45:09 +05301641{
1642 ASSERT(builtinFunc);
1643
1644 if (getType().getBasicType() == EbtFloat)
1645 {
1646 result->setFConst(builtinFunc(parameter.getFConst()));
1647 return true;
1648 }
1649
1650 infoSink.info.message(
1651 EPrefixInternalError, getLine(),
1652 "Unary operation not folded into constant");
1653 return false;
1654}
1655
Jamie Madillb1a85f42014-08-19 15:23:24 -04001656// static
Arun Patolebf790422015-05-18 17:53:04 +05301657TIntermTyped *TIntermConstantUnion::FoldAggregateBuiltIn(TOperator op, TIntermAggregate *aggregate, TInfoSink &infoSink)
Arun Patole274f0702015-05-05 13:33:30 +05301658{
1659 TIntermSequence *sequence = aggregate->getSequence();
1660 unsigned int paramsCount = sequence->size();
1661 std::vector<TConstantUnion *> unionArrays(paramsCount);
1662 std::vector<size_t> objectSizes(paramsCount);
1663 TType *maxSizeType = nullptr;
1664 TBasicType basicType = EbtVoid;
1665 TSourceLoc loc;
1666 for (unsigned int i = 0; i < paramsCount; i++)
1667 {
1668 TIntermConstantUnion *paramConstant = (*sequence)[i]->getAsConstantUnion();
1669 // Make sure that all params are constant before actual constant folding.
1670 if (!paramConstant)
1671 return nullptr;
1672
1673 if (i == 0)
1674 {
1675 basicType = paramConstant->getType().getBasicType();
1676 loc = paramConstant->getLine();
1677 }
1678 unionArrays[i] = paramConstant->getUnionArrayPointer();
1679 objectSizes[i] = paramConstant->getType().getObjectSize();
1680 if (maxSizeType == nullptr || (objectSizes[i] >= maxSizeType->getObjectSize()))
1681 maxSizeType = paramConstant->getTypePointer();
1682 }
1683
1684 size_t maxObjectSize = maxSizeType->getObjectSize();
1685 for (unsigned int i = 0; i < paramsCount; i++)
1686 if (objectSizes[i] != maxObjectSize)
1687 unionArrays[i] = Vectorize(*unionArrays[i], maxObjectSize);
1688
1689 TConstantUnion *tempConstArray = nullptr;
1690 TIntermConstantUnion *tempNode = nullptr;
1691 TType returnType = *maxSizeType;
1692 if (paramsCount == 2)
1693 {
1694 //
1695 // Binary built-in
1696 //
1697 switch (op)
1698 {
Arun Patolebf790422015-05-18 17:53:04 +05301699 case EOpAtan:
1700 {
1701 if (basicType == EbtFloat)
1702 {
1703 tempConstArray = new TConstantUnion[maxObjectSize];
1704 for (size_t i = 0; i < maxObjectSize; i++)
1705 {
1706 float y = unionArrays[0][i].getFConst();
1707 float x = unionArrays[1][i].getFConst();
1708 // Results are undefined if x and y are both 0.
1709 if (x == 0.0f && y == 0.0f)
1710 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &tempConstArray[i]);
1711 else
1712 tempConstArray[i].setFConst(atan2f(y, x));
1713 }
1714 }
1715 else
1716 UNREACHABLE();
1717 }
1718 break;
1719
1720 case EOpPow:
1721 {
1722 if (basicType == EbtFloat)
1723 {
1724 tempConstArray = new TConstantUnion[maxObjectSize];
1725 for (size_t i = 0; i < maxObjectSize; i++)
1726 {
1727 float x = unionArrays[0][i].getFConst();
1728 float y = unionArrays[1][i].getFConst();
1729 // Results are undefined if x < 0.
1730 // Results are undefined if x = 0 and y <= 0.
1731 if (x < 0.0f)
1732 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &tempConstArray[i]);
1733 else if (x == 0.0f && y <= 0.0f)
1734 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &tempConstArray[i]);
1735 else
1736 tempConstArray[i].setFConst(powf(x, y));
1737 }
1738 }
1739 else
1740 UNREACHABLE();
1741 }
1742 break;
1743
1744 case EOpMod:
1745 {
1746 if (basicType == EbtFloat)
1747 {
1748 tempConstArray = new TConstantUnion[maxObjectSize];
1749 for (size_t i = 0; i < maxObjectSize; i++)
1750 {
1751 float x = unionArrays[0][i].getFConst();
1752 float y = unionArrays[1][i].getFConst();
1753 tempConstArray[i].setFConst(x - y * floorf(x / y));
1754 }
1755 }
1756 else
1757 UNREACHABLE();
1758 }
1759 break;
1760
Arun Patole274f0702015-05-05 13:33:30 +05301761 case EOpMin:
1762 {
1763 tempConstArray = new TConstantUnion[maxObjectSize];
1764 for (size_t i = 0; i < maxObjectSize; i++)
1765 {
1766 switch (basicType)
1767 {
1768 case EbtFloat:
1769 tempConstArray[i].setFConst(std::min(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
1770 break;
1771 case EbtInt:
1772 tempConstArray[i].setIConst(std::min(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
1773 break;
1774 case EbtUInt:
1775 tempConstArray[i].setUConst(std::min(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
1776 break;
1777 default:
1778 UNREACHABLE();
1779 break;
1780 }
1781 }
1782 }
1783 break;
1784
1785 case EOpMax:
1786 {
1787 tempConstArray = new TConstantUnion[maxObjectSize];
1788 for (size_t i = 0; i < maxObjectSize; i++)
1789 {
1790 switch (basicType)
1791 {
1792 case EbtFloat:
1793 tempConstArray[i].setFConst(std::max(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
1794 break;
1795 case EbtInt:
1796 tempConstArray[i].setIConst(std::max(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
1797 break;
1798 case EbtUInt:
1799 tempConstArray[i].setUConst(std::max(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
1800 break;
1801 default:
1802 UNREACHABLE();
1803 break;
1804 }
1805 }
1806 }
1807 break;
1808
Arun Patolebf790422015-05-18 17:53:04 +05301809 case EOpStep:
1810 {
1811 if (basicType == EbtFloat)
1812 {
1813 tempConstArray = new TConstantUnion[maxObjectSize];
1814 for (size_t i = 0; i < maxObjectSize; i++)
1815 tempConstArray[i].setFConst(unionArrays[1][i].getFConst() < unionArrays[0][i].getFConst() ? 0.0f : 1.0f);
1816 }
1817 else
1818 UNREACHABLE();
1819 }
1820 break;
1821
Arun Patole9d0b1f92015-05-20 14:27:17 +05301822 case EOpLessThan:
1823 {
1824 tempConstArray = new TConstantUnion[maxObjectSize];
1825 for (size_t i = 0; i < maxObjectSize; i++)
1826 {
1827 switch (basicType)
1828 {
1829 case EbtFloat:
1830 tempConstArray[i].setBConst(unionArrays[0][i].getFConst() < unionArrays[1][i].getFConst());
1831 break;
1832 case EbtInt:
1833 tempConstArray[i].setBConst(unionArrays[0][i].getIConst() < unionArrays[1][i].getIConst());
1834 break;
1835 case EbtUInt:
1836 tempConstArray[i].setBConst(unionArrays[0][i].getUConst() < unionArrays[1][i].getUConst());
1837 break;
1838 default:
1839 UNREACHABLE();
1840 break;
1841 }
1842 }
1843 }
1844 break;
1845
1846 case EOpLessThanEqual:
1847 {
1848 tempConstArray = new TConstantUnion[maxObjectSize];
1849 for (size_t i = 0; i < maxObjectSize; i++)
1850 {
1851 switch (basicType)
1852 {
1853 case EbtFloat:
1854 tempConstArray[i].setBConst(unionArrays[0][i].getFConst() <= unionArrays[1][i].getFConst());
1855 break;
1856 case EbtInt:
1857 tempConstArray[i].setBConst(unionArrays[0][i].getIConst() <= unionArrays[1][i].getIConst());
1858 break;
1859 case EbtUInt:
1860 tempConstArray[i].setBConst(unionArrays[0][i].getUConst() <= unionArrays[1][i].getUConst());
1861 break;
1862 default:
1863 UNREACHABLE();
1864 break;
1865 }
1866 }
1867 }
1868 break;
1869
1870 case EOpGreaterThan:
1871 {
1872 tempConstArray = new TConstantUnion[maxObjectSize];
1873 for (size_t i = 0; i < maxObjectSize; i++)
1874 {
1875 switch (basicType)
1876 {
1877 case EbtFloat:
1878 tempConstArray[i].setBConst(unionArrays[0][i].getFConst() > unionArrays[1][i].getFConst());
1879 break;
1880 case EbtInt:
1881 tempConstArray[i].setBConst(unionArrays[0][i].getIConst() > unionArrays[1][i].getIConst());
1882 break;
1883 case EbtUInt:
1884 tempConstArray[i].setBConst(unionArrays[0][i].getUConst() > unionArrays[1][i].getUConst());
1885 break;
1886 default:
1887 UNREACHABLE();
1888 break;
1889 }
1890 }
1891 }
1892 break;
1893
1894 case EOpGreaterThanEqual:
1895 {
1896 tempConstArray = new TConstantUnion[maxObjectSize];
1897 for (size_t i = 0; i < maxObjectSize; i++)
1898 {
1899 switch (basicType)
1900 {
1901 case EbtFloat:
1902 tempConstArray[i].setBConst(unionArrays[0][i].getFConst() >= unionArrays[1][i].getFConst());
1903 break;
1904 case EbtInt:
1905 tempConstArray[i].setBConst(unionArrays[0][i].getIConst() >= unionArrays[1][i].getIConst());
1906 break;
1907 case EbtUInt:
1908 tempConstArray[i].setBConst(unionArrays[0][i].getUConst() >= unionArrays[1][i].getUConst());
1909 break;
1910 default:
1911 UNREACHABLE();
1912 break;
1913 }
1914 }
1915 }
1916 break;
1917
1918 case EOpVectorEqual:
1919 {
1920 tempConstArray = new TConstantUnion[maxObjectSize];
1921 for (size_t i = 0; i < maxObjectSize; i++)
1922 {
1923 switch (basicType)
1924 {
1925 case EbtFloat:
1926 tempConstArray[i].setBConst(unionArrays[0][i].getFConst() == unionArrays[1][i].getFConst());
1927 break;
1928 case EbtInt:
1929 tempConstArray[i].setBConst(unionArrays[0][i].getIConst() == unionArrays[1][i].getIConst());
1930 break;
1931 case EbtUInt:
1932 tempConstArray[i].setBConst(unionArrays[0][i].getUConst() == unionArrays[1][i].getUConst());
1933 break;
1934 case EbtBool:
1935 tempConstArray[i].setBConst(unionArrays[0][i].getBConst() == unionArrays[1][i].getBConst());
1936 break;
1937 default:
1938 UNREACHABLE();
1939 break;
1940 }
1941 }
1942 }
1943 break;
1944
1945 case EOpVectorNotEqual:
1946 {
1947 tempConstArray = new TConstantUnion[maxObjectSize];
1948 for (size_t i = 0; i < maxObjectSize; i++)
1949 {
1950 switch (basicType)
1951 {
1952 case EbtFloat:
1953 tempConstArray[i].setBConst(unionArrays[0][i].getFConst() != unionArrays[1][i].getFConst());
1954 break;
1955 case EbtInt:
1956 tempConstArray[i].setBConst(unionArrays[0][i].getIConst() != unionArrays[1][i].getIConst());
1957 break;
1958 case EbtUInt:
1959 tempConstArray[i].setBConst(unionArrays[0][i].getUConst() != unionArrays[1][i].getUConst());
1960 break;
1961 case EbtBool:
1962 tempConstArray[i].setBConst(unionArrays[0][i].getBConst() != unionArrays[1][i].getBConst());
1963 break;
1964 default:
1965 UNREACHABLE();
1966 break;
1967 }
1968 }
1969 }
1970 break;
1971
Arun Patole1155ddd2015-06-05 18:04:36 +05301972 case EOpDistance:
1973 if (basicType == EbtFloat)
1974 {
1975 TConstantUnion *distanceArray = new TConstantUnion[maxObjectSize];
1976 tempConstArray = new TConstantUnion();
1977 for (size_t i = 0; i < maxObjectSize; i++)
1978 {
1979 float x = unionArrays[0][i].getFConst();
1980 float y = unionArrays[1][i].getFConst();
1981 distanceArray[i].setFConst(x - y);
1982 }
1983 tempConstArray->setFConst(VectorLength(distanceArray, maxObjectSize));
1984 }
1985 else
1986 UNREACHABLE();
1987 break;
1988
1989 case EOpDot:
1990 if (basicType == EbtFloat)
1991 {
1992 tempConstArray = new TConstantUnion();
1993 tempConstArray->setFConst(VectorDotProduct(unionArrays[0], unionArrays[1], maxObjectSize));
1994 }
1995 else
1996 UNREACHABLE();
1997 break;
1998
1999 case EOpCross:
2000 if (basicType == EbtFloat && maxObjectSize == 3)
2001 {
2002 tempConstArray = new TConstantUnion[maxObjectSize];
2003 float x0 = unionArrays[0][0].getFConst();
2004 float x1 = unionArrays[0][1].getFConst();
2005 float x2 = unionArrays[0][2].getFConst();
2006 float y0 = unionArrays[1][0].getFConst();
2007 float y1 = unionArrays[1][1].getFConst();
2008 float y2 = unionArrays[1][2].getFConst();
2009 tempConstArray[0].setFConst(x1 * y2 - y1 * x2);
2010 tempConstArray[1].setFConst(x2 * y0 - y2 * x0);
2011 tempConstArray[2].setFConst(x0 * y1 - y0 * x1);
2012 }
2013 else
2014 UNREACHABLE();
2015 break;
2016
2017 case EOpReflect:
2018 if (basicType == EbtFloat)
2019 {
2020 // genType reflect (genType I, genType N) :
2021 // For the incident vector I and surface orientation N, returns the reflection direction:
2022 // I - 2 * dot(N, I) * N.
2023 tempConstArray = new TConstantUnion[maxObjectSize];
2024 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
2025 for (size_t i = 0; i < maxObjectSize; i++)
2026 {
2027 float result = unionArrays[0][i].getFConst() -
2028 2.0f * dotProduct * unionArrays[1][i].getFConst();
2029 tempConstArray[i].setFConst(result);
2030 }
2031 }
2032 else
2033 UNREACHABLE();
2034 break;
2035
Arun Patole274f0702015-05-05 13:33:30 +05302036 default:
2037 UNREACHABLE();
2038 // TODO: Add constant folding support for other built-in operations that take 2 parameters and not handled above.
2039 return nullptr;
2040 }
2041 }
2042 else if (paramsCount == 3)
2043 {
2044 //
2045 // Ternary built-in
2046 //
2047 switch (op)
2048 {
2049 case EOpClamp:
2050 {
2051 tempConstArray = new TConstantUnion[maxObjectSize];
2052 for (size_t i = 0; i < maxObjectSize; i++)
2053 {
2054 switch (basicType)
2055 {
2056 case EbtFloat:
2057 {
2058 float x = unionArrays[0][i].getFConst();
2059 float min = unionArrays[1][i].getFConst();
2060 float max = unionArrays[2][i].getFConst();
2061 // Results are undefined if min > max.
2062 if (min > max)
Arun Patole081c3f22015-05-25 15:43:35 +05302063 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &tempConstArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302064 else
2065 tempConstArray[i].setFConst(gl::clamp(x, min, max));
2066 }
2067 break;
2068 case EbtInt:
2069 {
2070 int x = unionArrays[0][i].getIConst();
2071 int min = unionArrays[1][i].getIConst();
2072 int max = unionArrays[2][i].getIConst();
2073 // Results are undefined if min > max.
2074 if (min > max)
Arun Patole081c3f22015-05-25 15:43:35 +05302075 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &tempConstArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302076 else
2077 tempConstArray[i].setIConst(gl::clamp(x, min, max));
2078 }
2079 break;
2080 case EbtUInt:
2081 {
2082 unsigned int x = unionArrays[0][i].getUConst();
2083 unsigned int min = unionArrays[1][i].getUConst();
2084 unsigned int max = unionArrays[2][i].getUConst();
2085 // Results are undefined if min > max.
2086 if (min > max)
Arun Patole081c3f22015-05-25 15:43:35 +05302087 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &tempConstArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302088 else
2089 tempConstArray[i].setUConst(gl::clamp(x, min, max));
2090 }
2091 break;
2092 default:
2093 UNREACHABLE();
2094 break;
2095 }
2096 }
2097 }
2098 break;
2099
Arun Patolebf790422015-05-18 17:53:04 +05302100 case EOpMix:
2101 {
2102 if (basicType == EbtFloat)
2103 {
2104 tempConstArray = new TConstantUnion[maxObjectSize];
2105 for (size_t i = 0; i < maxObjectSize; i++)
2106 {
2107 float x = unionArrays[0][i].getFConst();
2108 float y = unionArrays[1][i].getFConst();
2109 TBasicType type = (*sequence)[2]->getAsTyped()->getType().getBasicType();
2110 if (type == EbtFloat)
2111 {
2112 // Returns the linear blend of x and y, i.e., x * (1 - a) + y * a.
2113 float a = unionArrays[2][i].getFConst();
2114 tempConstArray[i].setFConst(x * (1.0f - a) + y * a);
2115 }
2116 else // 3rd parameter is EbtBool
2117 {
2118 ASSERT(type == EbtBool);
2119 // Selects which vector each returned component comes from.
2120 // For a component of a that is false, the corresponding component of x is returned.
2121 // For a component of a that is true, the corresponding component of y is returned.
2122 bool a = unionArrays[2][i].getBConst();
2123 tempConstArray[i].setFConst(a ? y : x);
2124 }
2125 }
2126 }
2127 else
2128 UNREACHABLE();
2129 }
2130 break;
2131
2132 case EOpSmoothStep:
2133 {
2134 if (basicType == EbtFloat)
2135 {
2136 tempConstArray = new TConstantUnion[maxObjectSize];
2137 for (size_t i = 0; i < maxObjectSize; i++)
2138 {
2139 float edge0 = unionArrays[0][i].getFConst();
2140 float edge1 = unionArrays[1][i].getFConst();
2141 float x = unionArrays[2][i].getFConst();
2142 // Results are undefined if edge0 >= edge1.
2143 if (edge0 >= edge1)
2144 {
2145 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &tempConstArray[i]);
2146 }
2147 else
2148 {
2149 // Returns 0.0 if x <= edge0 and 1.0 if x >= edge1 and performs smooth
2150 // Hermite interpolation between 0 and 1 when edge0 < x < edge1.
2151 float t = gl::clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f);
2152 tempConstArray[i].setFConst(t * t * (3.0f - 2.0f * t));
2153 }
2154 }
2155 }
2156 else
2157 UNREACHABLE();
2158 }
2159 break;
2160
Arun Patole1155ddd2015-06-05 18:04:36 +05302161 case EOpFaceForward:
2162 if (basicType == EbtFloat)
2163 {
2164 // genType faceforward(genType N, genType I, genType Nref) :
2165 // If dot(Nref, I) < 0 return N, otherwise return -N.
2166 tempConstArray = new TConstantUnion[maxObjectSize];
2167 float dotProduct = VectorDotProduct(unionArrays[2], unionArrays[1], maxObjectSize);
2168 for (size_t i = 0; i < maxObjectSize; i++)
2169 {
2170 if (dotProduct < 0)
2171 tempConstArray[i].setFConst(unionArrays[0][i].getFConst());
2172 else
2173 tempConstArray[i].setFConst(-unionArrays[0][i].getFConst());
2174 }
2175 }
2176 else
2177 UNREACHABLE();
2178 break;
2179
2180 case EOpRefract:
2181 if (basicType == EbtFloat)
2182 {
2183 // genType refract(genType I, genType N, float eta) :
2184 // For the incident vector I and surface normal N, and the ratio of indices of refraction eta,
2185 // return the refraction vector. The result is computed by
2186 // k = 1.0 - eta * eta * (1.0 - dot(N, I) * dot(N, I))
2187 // if (k < 0.0)
2188 // return genType(0.0)
2189 // else
2190 // return eta * I - (eta * dot(N, I) + sqrt(k)) * N
2191 tempConstArray = new TConstantUnion[maxObjectSize];
2192 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
2193 for (size_t i = 0; i < maxObjectSize; i++)
2194 {
2195 float eta = unionArrays[2][i].getFConst();
2196 float k = 1.0f - eta * eta * (1.0f - dotProduct * dotProduct);
2197 if (k < 0.0f)
2198 tempConstArray[i].setFConst(0.0f);
2199 else
2200 tempConstArray[i].setFConst(eta * unionArrays[0][i].getFConst() -
2201 (eta * dotProduct + sqrtf(k)) * unionArrays[1][i].getFConst());
2202 }
2203 }
2204 else
2205 UNREACHABLE();
2206 break;
2207
Arun Patole274f0702015-05-05 13:33:30 +05302208 default:
2209 UNREACHABLE();
2210 // TODO: Add constant folding support for other built-in operations that take 3 parameters and not handled above.
2211 return nullptr;
2212 }
2213 }
2214
2215 if (tempConstArray)
2216 {
2217 tempNode = new TIntermConstantUnion(tempConstArray, returnType);
2218 tempNode->setLine(loc);
2219 }
2220 return tempNode;
2221}
2222
2223// static
Jamie Madillb1a85f42014-08-19 15:23:24 -04002224TString TIntermTraverser::hash(const TString &name, ShHashFunction64 hashFunction)
2225{
2226 if (hashFunction == NULL || name.empty())
2227 return name;
2228 khronos_uint64_t number = (*hashFunction)(name.c_str(), name.length());
2229 TStringStream stream;
2230 stream << HASHED_NAME_PREFIX << std::hex << number;
2231 TString hashedName = stream.str();
2232 return hashedName;
2233}
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002234
2235void TIntermTraverser::updateTree()
2236{
Olli Etuahoa6f22092015-05-08 18:31:10 +03002237 for (size_t ii = 0; ii < mInsertions.size(); ++ii)
2238 {
2239 const NodeInsertMultipleEntry &insertion = mInsertions[ii];
2240 ASSERT(insertion.parent);
2241 bool inserted = insertion.parent->insertChildNodes(insertion.position, insertion.insertions);
2242 ASSERT(inserted);
2243 UNUSED_ASSERTION_VARIABLE(inserted);
2244 }
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002245 for (size_t ii = 0; ii < mReplacements.size(); ++ii)
2246 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03002247 const NodeUpdateEntry &replacement = mReplacements[ii];
2248 ASSERT(replacement.parent);
2249 bool replaced = replacement.parent->replaceChildNode(
2250 replacement.original, replacement.replacement);
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002251 ASSERT(replaced);
Olli Etuahod57e0db2015-04-24 15:05:08 +03002252 UNUSED_ASSERTION_VARIABLE(replaced);
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002253
Olli Etuahocd94ef92015-04-16 19:18:10 +03002254 if (!replacement.originalBecomesChildOfReplacement)
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002255 {
2256 // In AST traversing, a parent is visited before its children.
Olli Etuahocd94ef92015-04-16 19:18:10 +03002257 // After we replace a node, if its immediate child is to
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002258 // be replaced, we need to make sure we don't update the replaced
2259 // node; instead, we update the replacement node.
2260 for (size_t jj = ii + 1; jj < mReplacements.size(); ++jj)
2261 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03002262 NodeUpdateEntry &replacement2 = mReplacements[jj];
2263 if (replacement2.parent == replacement.original)
2264 replacement2.parent = replacement.replacement;
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002265 }
2266 }
2267 }
Olli Etuahofc0e2bc2015-04-16 13:39:56 +03002268 for (size_t ii = 0; ii < mMultiReplacements.size(); ++ii)
2269 {
2270 const NodeReplaceWithMultipleEntry &replacement = mMultiReplacements[ii];
2271 ASSERT(replacement.parent);
2272 bool replaced = replacement.parent->replaceChildNodeWithMultiple(
2273 replacement.original, replacement.replacements);
2274 ASSERT(replaced);
Olli Etuahod57e0db2015-04-24 15:05:08 +03002275 UNUSED_ASSERTION_VARIABLE(replaced);
Olli Etuahofc0e2bc2015-04-16 13:39:56 +03002276 }
Olli Etuahod4f303e2015-05-20 17:09:06 +03002277
2278 mInsertions.clear();
2279 mReplacements.clear();
2280 mMultiReplacements.clear();
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002281}