blob: e2a69fd1306adfa60eeb4713501fefa69e5b8b3b [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 Patole2decb4b2015-05-25 19:20:26 +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
386//
387// returns true if the operator is for one of the constructors
388//
389bool TIntermOperator::isConstructor() const
390{
391 switch (mOp)
392 {
393 case EOpConstructVec2:
394 case EOpConstructVec3:
395 case EOpConstructVec4:
396 case EOpConstructMat2:
397 case EOpConstructMat3:
398 case EOpConstructMat4:
399 case EOpConstructFloat:
400 case EOpConstructIVec2:
401 case EOpConstructIVec3:
402 case EOpConstructIVec4:
403 case EOpConstructInt:
404 case EOpConstructUVec2:
405 case EOpConstructUVec3:
406 case EOpConstructUVec4:
407 case EOpConstructUInt:
408 case EOpConstructBVec2:
409 case EOpConstructBVec3:
410 case EOpConstructBVec4:
411 case EOpConstructBool:
412 case EOpConstructStruct:
413 return true;
414 default:
415 return false;
416 }
417}
418
419//
420// Make sure the type of a unary operator is appropriate for its
421// combination of operation and operand type.
422//
Olli Etuahof6c694b2015-03-26 14:50:53 +0200423void TIntermUnary::promote(const TType *funcReturnType)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400424{
425 switch (mOp)
426 {
Olli Etuahodca3e792015-03-26 13:24:04 +0200427 case EOpFloatBitsToInt:
428 case EOpFloatBitsToUint:
Olli Etuahoe8d2c072015-01-08 16:33:54 +0200429 case EOpIntBitsToFloat:
430 case EOpUintBitsToFloat:
Olli Etuahodca3e792015-03-26 13:24:04 +0200431 case EOpPackSnorm2x16:
432 case EOpPackUnorm2x16:
433 case EOpPackHalf2x16:
Olli Etuaho7700ff62015-01-15 12:16:29 +0200434 case EOpUnpackSnorm2x16:
435 case EOpUnpackUnorm2x16:
Olli Etuahodca3e792015-03-26 13:24:04 +0200436 mType.setPrecision(EbpHigh);
Arun Patole6b19d762015-02-19 09:40:39 +0530437 break;
Olli Etuahodca3e792015-03-26 13:24:04 +0200438 case EOpUnpackHalf2x16:
439 mType.setPrecision(EbpMedium);
440 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400441 default:
Olli Etuahodca3e792015-03-26 13:24:04 +0200442 setType(mOperand->getType());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400443 }
444
Olli Etuahof6c694b2015-03-26 14:50:53 +0200445 if (funcReturnType != nullptr)
446 {
447 if (funcReturnType->getBasicType() == EbtBool)
448 {
449 // Bool types should not have precision.
450 setType(*funcReturnType);
451 }
452 else
453 {
454 // Precision of the node has been set based on the operand.
455 setTypePreservePrecision(*funcReturnType);
456 }
457 }
458
Jamie Madillb1a85f42014-08-19 15:23:24 -0400459 mType.setQualifier(EvqTemporary);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400460}
461
462//
463// Establishes the type of the resultant operation, as well as
464// makes the operator the correct one for the operands.
465//
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200466// For lots of operations it should already be established that the operand
467// combination is valid, but returns false if operator can't work on operands.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400468//
469bool TIntermBinary::promote(TInfoSink &infoSink)
470{
Olli Etuahoe79904c2015-03-18 16:56:42 +0200471 ASSERT(mLeft->isArray() == mRight->isArray());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400472
Jamie Madillb1a85f42014-08-19 15:23:24 -0400473 //
474 // Base assumption: just make the type the same as the left
475 // operand. Then only deviations from this need be coded.
476 //
477 setType(mLeft->getType());
478
479 // The result gets promoted to the highest precision.
480 TPrecision higherPrecision = GetHigherPrecision(
481 mLeft->getPrecision(), mRight->getPrecision());
482 getTypePointer()->setPrecision(higherPrecision);
483
484 // Binary operations results in temporary variables unless both
485 // operands are const.
486 if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst)
487 {
488 getTypePointer()->setQualifier(EvqTemporary);
489 }
490
491 const int nominalSize =
492 std::max(mLeft->getNominalSize(), mRight->getNominalSize());
493
494 //
495 // All scalars or structs. Code after this test assumes this case is removed!
496 //
497 if (nominalSize == 1)
498 {
499 switch (mOp)
500 {
501 //
502 // Promote to conditional
503 //
504 case EOpEqual:
505 case EOpNotEqual:
506 case EOpLessThan:
507 case EOpGreaterThan:
508 case EOpLessThanEqual:
509 case EOpGreaterThanEqual:
510 setType(TType(EbtBool, EbpUndefined));
511 break;
512
513 //
514 // And and Or operate on conditionals
515 //
516 case EOpLogicalAnd:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200517 case EOpLogicalXor:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400518 case EOpLogicalOr:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200519 ASSERT(mLeft->getBasicType() == EbtBool && mRight->getBasicType() == EbtBool);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400520 setType(TType(EbtBool, EbpUndefined));
521 break;
522
523 default:
524 break;
525 }
526 return true;
527 }
528
529 // If we reach here, at least one of the operands is vector or matrix.
530 // The other operand could be a scalar, vector, or matrix.
531 // Can these two operands be combined?
532 //
533 TBasicType basicType = mLeft->getBasicType();
534 switch (mOp)
535 {
536 case EOpMul:
537 if (!mLeft->isMatrix() && mRight->isMatrix())
538 {
539 if (mLeft->isVector())
540 {
541 mOp = EOpVectorTimesMatrix;
542 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700543 static_cast<unsigned char>(mRight->getCols()), 1));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400544 }
545 else
546 {
547 mOp = EOpMatrixTimesScalar;
548 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700549 static_cast<unsigned char>(mRight->getCols()), static_cast<unsigned char>(mRight->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400550 }
551 }
552 else if (mLeft->isMatrix() && !mRight->isMatrix())
553 {
554 if (mRight->isVector())
555 {
556 mOp = EOpMatrixTimesVector;
557 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700558 static_cast<unsigned char>(mLeft->getRows()), 1));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400559 }
560 else
561 {
562 mOp = EOpMatrixTimesScalar;
563 }
564 }
565 else if (mLeft->isMatrix() && mRight->isMatrix())
566 {
567 mOp = EOpMatrixTimesMatrix;
568 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700569 static_cast<unsigned char>(mRight->getCols()), static_cast<unsigned char>(mLeft->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400570 }
571 else if (!mLeft->isMatrix() && !mRight->isMatrix())
572 {
573 if (mLeft->isVector() && mRight->isVector())
574 {
575 // leave as component product
576 }
577 else if (mLeft->isVector() || mRight->isVector())
578 {
579 mOp = EOpVectorTimesScalar;
580 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700581 static_cast<unsigned char>(nominalSize), 1));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400582 }
583 }
584 else
585 {
586 infoSink.info.message(EPrefixInternalError, getLine(),
587 "Missing elses");
588 return false;
589 }
590
591 if (!ValidateMultiplication(mOp, mLeft->getType(), mRight->getType()))
592 {
593 return false;
594 }
595 break;
596
597 case EOpMulAssign:
598 if (!mLeft->isMatrix() && mRight->isMatrix())
599 {
600 if (mLeft->isVector())
601 {
602 mOp = EOpVectorTimesMatrixAssign;
603 }
604 else
605 {
606 return false;
607 }
608 }
609 else if (mLeft->isMatrix() && !mRight->isMatrix())
610 {
611 if (mRight->isVector())
612 {
613 return false;
614 }
615 else
616 {
617 mOp = EOpMatrixTimesScalarAssign;
618 }
619 }
620 else if (mLeft->isMatrix() && mRight->isMatrix())
621 {
622 mOp = EOpMatrixTimesMatrixAssign;
623 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700624 static_cast<unsigned char>(mRight->getCols()), static_cast<unsigned char>(mLeft->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400625 }
626 else if (!mLeft->isMatrix() && !mRight->isMatrix())
627 {
628 if (mLeft->isVector() && mRight->isVector())
629 {
630 // leave as component product
631 }
632 else if (mLeft->isVector() || mRight->isVector())
633 {
634 if (!mLeft->isVector())
635 return false;
636 mOp = EOpVectorTimesScalarAssign;
637 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700638 static_cast<unsigned char>(mLeft->getNominalSize()), 1));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400639 }
640 }
641 else
642 {
643 infoSink.info.message(EPrefixInternalError, getLine(),
644 "Missing elses");
645 return false;
646 }
647
648 if (!ValidateMultiplication(mOp, mLeft->getType(), mRight->getType()))
649 {
650 return false;
651 }
652 break;
653
654 case EOpAssign:
655 case EOpInitialize:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200656 // No more additional checks are needed.
657 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
658 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
659 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400660 case EOpAdd:
661 case EOpSub:
662 case EOpDiv:
Olli Etuahoff805cc2015-02-13 10:59:34 +0200663 case EOpIMod:
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200664 case EOpBitShiftLeft:
665 case EOpBitShiftRight:
666 case EOpBitwiseAnd:
667 case EOpBitwiseXor:
668 case EOpBitwiseOr:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400669 case EOpAddAssign:
670 case EOpSubAssign:
671 case EOpDivAssign:
Olli Etuahoff805cc2015-02-13 10:59:34 +0200672 case EOpIModAssign:
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200673 case EOpBitShiftLeftAssign:
674 case EOpBitShiftRightAssign:
675 case EOpBitwiseAndAssign:
676 case EOpBitwiseXorAssign:
677 case EOpBitwiseOrAssign:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400678 if ((mLeft->isMatrix() && mRight->isVector()) ||
679 (mLeft->isVector() && mRight->isMatrix()))
680 {
681 return false;
682 }
683
684 // Are the sizes compatible?
685 if (mLeft->getNominalSize() != mRight->getNominalSize() ||
686 mLeft->getSecondarySize() != mRight->getSecondarySize())
687 {
Olli Etuaho6c850472014-12-02 16:23:17 +0200688 // If the nominal sizes of operands do not match:
689 // One of them must be a scalar.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400690 if (!mLeft->isScalar() && !mRight->isScalar())
691 return false;
692
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200693 // In the case of compound assignment other than multiply-assign,
694 // the right side needs to be a scalar. Otherwise a vector/matrix
695 // would be assigned to a scalar. A scalar can't be shifted by a
696 // vector either.
Olli Etuaho6c850472014-12-02 16:23:17 +0200697 if (!mRight->isScalar() &&
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200698 (isAssignment() ||
699 mOp == EOpBitShiftLeft ||
700 mOp == EOpBitShiftRight))
Olli Etuaho6c850472014-12-02 16:23:17 +0200701 return false;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400702 }
703
704 {
705 const int secondarySize = std::max(
706 mLeft->getSecondarySize(), mRight->getSecondarySize());
707 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700708 static_cast<unsigned char>(nominalSize), static_cast<unsigned char>(secondarySize)));
Olli Etuahoe79904c2015-03-18 16:56:42 +0200709 if (mLeft->isArray())
710 {
711 ASSERT(mLeft->getArraySize() == mRight->getArraySize());
712 mType.setArraySize(mLeft->getArraySize());
713 }
Jamie Madillb1a85f42014-08-19 15:23:24 -0400714 }
715 break;
716
717 case EOpEqual:
718 case EOpNotEqual:
719 case EOpLessThan:
720 case EOpGreaterThan:
721 case EOpLessThanEqual:
722 case EOpGreaterThanEqual:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200723 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
724 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400725 setType(TType(EbtBool, EbpUndefined));
726 break;
727
728 default:
729 return false;
730 }
731 return true;
732}
733
734//
735// The fold functions see if an operation on a constant can be done in place,
736// without generating run-time code.
737//
738// Returns the node to keep using, which may or may not be the node passed in.
739//
740TIntermTyped *TIntermConstantUnion::fold(
Olli Etuaho2cb7b832015-04-23 20:27:44 +0300741 TOperator op, TIntermConstantUnion *rightNode, TInfoSink &infoSink)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400742{
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400743 TConstantUnion *unionArray = getUnionArrayPointer();
Jamie Madillb1a85f42014-08-19 15:23:24 -0400744
745 if (!unionArray)
Arun Patolefddc2112015-04-22 13:28:10 +0530746 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400747
748 size_t objectSize = getType().getObjectSize();
749
Olli Etuaho2cb7b832015-04-23 20:27:44 +0300750 if (rightNode)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400751 {
752 // binary operations
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400753 TConstantUnion *rightUnionArray = rightNode->getUnionArrayPointer();
Jamie Madillb1a85f42014-08-19 15:23:24 -0400754 TType returnType = getType();
755
756 if (!rightUnionArray)
Arun Patolefddc2112015-04-22 13:28:10 +0530757 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400758
Olli Etuaho2cb7b832015-04-23 20:27:44 +0300759 // for a case like float f = vec4(2, 3, 4, 5) + 1.2;
760 if (rightNode->getType().getObjectSize() == 1 && objectSize > 1)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400761 {
Arun Patole274f0702015-05-05 13:33:30 +0530762 rightUnionArray = Vectorize(*rightNode->getUnionArrayPointer(), objectSize);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400763 returnType = getType();
764 }
Olli Etuaho2cb7b832015-04-23 20:27:44 +0300765 else if (rightNode->getType().getObjectSize() > 1 && objectSize == 1)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400766 {
Olli Etuaho2cb7b832015-04-23 20:27:44 +0300767 // for a case like float f = 1.2 + vec4(2, 3, 4, 5);
Arun Patole274f0702015-05-05 13:33:30 +0530768 unionArray = Vectorize(*getUnionArrayPointer(), rightNode->getType().getObjectSize());
Olli Etuaho2cb7b832015-04-23 20:27:44 +0300769 returnType = rightNode->getType();
770 objectSize = rightNode->getType().getObjectSize();
Jamie Madillb1a85f42014-08-19 15:23:24 -0400771 }
772
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400773 TConstantUnion *tempConstArray = nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400774 TIntermConstantUnion *tempNode;
775
776 bool boolNodeFlag = false;
777 switch(op)
778 {
779 case EOpAdd:
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400780 tempConstArray = new TConstantUnion[objectSize];
Jamie Madillb1a85f42014-08-19 15:23:24 -0400781 for (size_t i = 0; i < objectSize; i++)
782 tempConstArray[i] = unionArray[i] + rightUnionArray[i];
783 break;
784 case EOpSub:
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400785 tempConstArray = new TConstantUnion[objectSize];
Jamie Madillb1a85f42014-08-19 15:23:24 -0400786 for (size_t i = 0; i < objectSize; i++)
787 tempConstArray[i] = unionArray[i] - rightUnionArray[i];
788 break;
789
790 case EOpMul:
791 case EOpVectorTimesScalar:
792 case EOpMatrixTimesScalar:
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400793 tempConstArray = new TConstantUnion[objectSize];
Jamie Madillb1a85f42014-08-19 15:23:24 -0400794 for (size_t i = 0; i < objectSize; i++)
795 tempConstArray[i] = unionArray[i] * rightUnionArray[i];
796 break;
797
798 case EOpMatrixTimesMatrix:
799 {
800 if (getType().getBasicType() != EbtFloat ||
Olli Etuaho2cb7b832015-04-23 20:27:44 +0300801 rightNode->getBasicType() != EbtFloat)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400802 {
803 infoSink.info.message(
804 EPrefixInternalError, getLine(),
805 "Constant Folding cannot be done for matrix multiply");
Arun Patolefddc2112015-04-22 13:28:10 +0530806 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400807 }
808
809 const int leftCols = getCols();
810 const int leftRows = getRows();
Olli Etuaho2cb7b832015-04-23 20:27:44 +0300811 const int rightCols = rightNode->getType().getCols();
812 const int rightRows = rightNode->getType().getRows();
Jamie Madillb1a85f42014-08-19 15:23:24 -0400813 const int resultCols = rightCols;
814 const int resultRows = leftRows;
815
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400816 tempConstArray = new TConstantUnion[resultCols * resultRows];
Jamie Madillb1a85f42014-08-19 15:23:24 -0400817 for (int row = 0; row < resultRows; row++)
818 {
819 for (int column = 0; column < resultCols; column++)
820 {
821 tempConstArray[resultRows * column + row].setFConst(0.0f);
822 for (int i = 0; i < leftCols; i++)
823 {
824 tempConstArray[resultRows * column + row].setFConst(
825 tempConstArray[resultRows * column + row].getFConst() +
826 unionArray[i * leftRows + row].getFConst() *
827 rightUnionArray[column * rightRows + i].getFConst());
828 }
829 }
830 }
831
832 // update return type for matrix product
Minmin Gong794e0002015-04-07 18:31:54 -0700833 returnType.setPrimarySize(static_cast<unsigned char>(resultCols));
834 returnType.setSecondarySize(static_cast<unsigned char>(resultRows));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400835 }
836 break;
837
838 case EOpDiv:
Olli Etuahoff805cc2015-02-13 10:59:34 +0200839 case EOpIMod:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400840 {
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400841 tempConstArray = new TConstantUnion[objectSize];
Jamie Madillb1a85f42014-08-19 15:23:24 -0400842 for (size_t i = 0; i < objectSize; i++)
843 {
844 switch (getType().getBasicType())
845 {
846 case EbtFloat:
847 if (rightUnionArray[i] == 0.0f)
848 {
849 infoSink.info.message(
850 EPrefixWarning, getLine(),
851 "Divide by zero error during constant folding");
852 tempConstArray[i].setFConst(
853 unionArray[i].getFConst() < 0 ? -FLT_MAX : FLT_MAX);
854 }
855 else
856 {
Olli Etuaho3eab00a2015-02-12 16:02:39 +0200857 ASSERT(op == EOpDiv);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400858 tempConstArray[i].setFConst(
859 unionArray[i].getFConst() /
860 rightUnionArray[i].getFConst());
861 }
862 break;
863
864 case EbtInt:
865 if (rightUnionArray[i] == 0)
866 {
867 infoSink.info.message(
868 EPrefixWarning, getLine(),
869 "Divide by zero error during constant folding");
870 tempConstArray[i].setIConst(INT_MAX);
871 }
872 else
873 {
Olli Etuaho3eab00a2015-02-12 16:02:39 +0200874 if (op == EOpDiv)
875 {
876 tempConstArray[i].setIConst(
877 unionArray[i].getIConst() /
878 rightUnionArray[i].getIConst());
879 }
880 else
881 {
882 ASSERT(op == EOpIMod);
883 tempConstArray[i].setIConst(
884 unionArray[i].getIConst() %
885 rightUnionArray[i].getIConst());
886 }
Jamie Madillb1a85f42014-08-19 15:23:24 -0400887 }
888 break;
889
890 case EbtUInt:
891 if (rightUnionArray[i] == 0)
892 {
893 infoSink.info.message(
894 EPrefixWarning, getLine(),
895 "Divide by zero error during constant folding");
896 tempConstArray[i].setUConst(UINT_MAX);
897 }
898 else
899 {
Olli Etuaho3eab00a2015-02-12 16:02:39 +0200900 if (op == EOpDiv)
901 {
902 tempConstArray[i].setUConst(
903 unionArray[i].getUConst() /
904 rightUnionArray[i].getUConst());
905 }
906 else
907 {
908 ASSERT(op == EOpIMod);
909 tempConstArray[i].setUConst(
910 unionArray[i].getUConst() %
911 rightUnionArray[i].getUConst());
912 }
Jamie Madillb1a85f42014-08-19 15:23:24 -0400913 }
914 break;
915
916 default:
917 infoSink.info.message(
918 EPrefixInternalError, getLine(),
919 "Constant folding cannot be done for \"/\"");
Arun Patolefddc2112015-04-22 13:28:10 +0530920 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400921 }
922 }
923 }
924 break;
925
926 case EOpMatrixTimesVector:
927 {
Olli Etuaho2cb7b832015-04-23 20:27:44 +0300928 if (rightNode->getBasicType() != EbtFloat)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400929 {
930 infoSink.info.message(
931 EPrefixInternalError, getLine(),
932 "Constant Folding cannot be done for matrix times vector");
Arun Patolefddc2112015-04-22 13:28:10 +0530933 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400934 }
935
936 const int matrixCols = getCols();
937 const int matrixRows = getRows();
938
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400939 tempConstArray = new TConstantUnion[matrixRows];
Jamie Madillb1a85f42014-08-19 15:23:24 -0400940
941 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
942 {
943 tempConstArray[matrixRow].setFConst(0.0f);
944 for (int col = 0; col < matrixCols; col++)
945 {
946 tempConstArray[matrixRow].setFConst(
947 tempConstArray[matrixRow].getFConst() +
948 unionArray[col * matrixRows + matrixRow].getFConst() *
949 rightUnionArray[col].getFConst());
950 }
951 }
952
Olli Etuaho2cb7b832015-04-23 20:27:44 +0300953 returnType = rightNode->getType();
Minmin Gong794e0002015-04-07 18:31:54 -0700954 returnType.setPrimarySize(static_cast<unsigned char>(matrixRows));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400955
956 tempNode = new TIntermConstantUnion(tempConstArray, returnType);
957 tempNode->setLine(getLine());
958
959 return tempNode;
960 }
961
962 case EOpVectorTimesMatrix:
963 {
964 if (getType().getBasicType() != EbtFloat)
965 {
966 infoSink.info.message(
967 EPrefixInternalError, getLine(),
968 "Constant Folding cannot be done for vector times matrix");
Arun Patolefddc2112015-04-22 13:28:10 +0530969 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400970 }
971
Olli Etuaho2cb7b832015-04-23 20:27:44 +0300972 const int matrixCols = rightNode->getType().getCols();
973 const int matrixRows = rightNode->getType().getRows();
Jamie Madillb1a85f42014-08-19 15:23:24 -0400974
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400975 tempConstArray = new TConstantUnion[matrixCols];
Jamie Madillb1a85f42014-08-19 15:23:24 -0400976
977 for (int matrixCol = 0; matrixCol < matrixCols; matrixCol++)
978 {
979 tempConstArray[matrixCol].setFConst(0.0f);
980 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
981 {
982 tempConstArray[matrixCol].setFConst(
983 tempConstArray[matrixCol].getFConst() +
984 unionArray[matrixRow].getFConst() *
985 rightUnionArray[matrixCol * matrixRows + matrixRow].getFConst());
986 }
987 }
988
Minmin Gong794e0002015-04-07 18:31:54 -0700989 returnType.setPrimarySize(static_cast<unsigned char>(matrixCols));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400990 }
991 break;
992
993 case EOpLogicalAnd:
994 // this code is written for possible future use,
995 // will not get executed currently
996 {
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400997 tempConstArray = new TConstantUnion[objectSize];
Jamie Madillb1a85f42014-08-19 15:23:24 -0400998 for (size_t i = 0; i < objectSize; i++)
999 {
1000 tempConstArray[i] = unionArray[i] && rightUnionArray[i];
1001 }
1002 }
1003 break;
1004
1005 case EOpLogicalOr:
1006 // this code is written for possible future use,
1007 // will not get executed currently
1008 {
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001009 tempConstArray = new TConstantUnion[objectSize];
Jamie Madillb1a85f42014-08-19 15:23:24 -04001010 for (size_t i = 0; i < objectSize; i++)
1011 {
1012 tempConstArray[i] = unionArray[i] || rightUnionArray[i];
1013 }
1014 }
1015 break;
1016
1017 case EOpLogicalXor:
1018 {
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001019 tempConstArray = new TConstantUnion[objectSize];
Jamie Madillb1a85f42014-08-19 15:23:24 -04001020 for (size_t i = 0; i < objectSize; i++)
1021 {
1022 switch (getType().getBasicType())
1023 {
1024 case EbtBool:
1025 tempConstArray[i].setBConst(
1026 unionArray[i] == rightUnionArray[i] ? false : true);
1027 break;
1028 default:
1029 UNREACHABLE();
1030 break;
1031 }
1032 }
1033 }
1034 break;
1035
Olli Etuaho31b5fc62015-01-16 12:13:36 +02001036 case EOpBitwiseAnd:
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001037 tempConstArray = new TConstantUnion[objectSize];
Olli Etuaho31b5fc62015-01-16 12:13:36 +02001038 for (size_t i = 0; i < objectSize; i++)
1039 tempConstArray[i] = unionArray[i] & rightUnionArray[i];
1040 break;
1041 case EOpBitwiseXor:
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001042 tempConstArray = new TConstantUnion[objectSize];
Olli Etuaho31b5fc62015-01-16 12:13:36 +02001043 for (size_t i = 0; i < objectSize; i++)
1044 tempConstArray[i] = unionArray[i] ^ rightUnionArray[i];
1045 break;
1046 case EOpBitwiseOr:
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001047 tempConstArray = new TConstantUnion[objectSize];
Olli Etuaho31b5fc62015-01-16 12:13:36 +02001048 for (size_t i = 0; i < objectSize; i++)
1049 tempConstArray[i] = unionArray[i] | rightUnionArray[i];
1050 break;
1051 case EOpBitShiftLeft:
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001052 tempConstArray = new TConstantUnion[objectSize];
Olli Etuaho31b5fc62015-01-16 12:13:36 +02001053 for (size_t i = 0; i < objectSize; i++)
1054 tempConstArray[i] = unionArray[i] << rightUnionArray[i];
1055 break;
1056 case EOpBitShiftRight:
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001057 tempConstArray = new TConstantUnion[objectSize];
Olli Etuaho31b5fc62015-01-16 12:13:36 +02001058 for (size_t i = 0; i < objectSize; i++)
1059 tempConstArray[i] = unionArray[i] >> rightUnionArray[i];
1060 break;
1061
Jamie Madillb1a85f42014-08-19 15:23:24 -04001062 case EOpLessThan:
1063 ASSERT(objectSize == 1);
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001064 tempConstArray = new TConstantUnion[1];
Jamie Madillb1a85f42014-08-19 15:23:24 -04001065 tempConstArray->setBConst(*unionArray < *rightUnionArray);
1066 returnType = TType(EbtBool, EbpUndefined, EvqConst);
1067 break;
1068
1069 case EOpGreaterThan:
1070 ASSERT(objectSize == 1);
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001071 tempConstArray = new TConstantUnion[1];
Jamie Madillb1a85f42014-08-19 15:23:24 -04001072 tempConstArray->setBConst(*unionArray > *rightUnionArray);
1073 returnType = TType(EbtBool, EbpUndefined, EvqConst);
1074 break;
1075
1076 case EOpLessThanEqual:
1077 {
1078 ASSERT(objectSize == 1);
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001079 TConstantUnion constant;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001080 constant.setBConst(*unionArray > *rightUnionArray);
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001081 tempConstArray = new TConstantUnion[1];
Jamie Madillb1a85f42014-08-19 15:23:24 -04001082 tempConstArray->setBConst(!constant.getBConst());
1083 returnType = TType(EbtBool, EbpUndefined, EvqConst);
1084 break;
1085 }
1086
1087 case EOpGreaterThanEqual:
1088 {
1089 ASSERT(objectSize == 1);
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001090 TConstantUnion constant;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001091 constant.setBConst(*unionArray < *rightUnionArray);
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001092 tempConstArray = new TConstantUnion[1];
Jamie Madillb1a85f42014-08-19 15:23:24 -04001093 tempConstArray->setBConst(!constant.getBConst());
1094 returnType = TType(EbtBool, EbpUndefined, EvqConst);
1095 break;
1096 }
1097
1098 case EOpEqual:
1099 if (getType().getBasicType() == EbtStruct)
1100 {
Olli Etuaho2cb7b832015-04-23 20:27:44 +03001101 if (!CompareStructure(rightNode->getType(),
1102 rightNode->getUnionArrayPointer(),
Jamie Madillb1a85f42014-08-19 15:23:24 -04001103 unionArray))
1104 {
1105 boolNodeFlag = true;
1106 }
1107 }
1108 else
1109 {
1110 for (size_t i = 0; i < objectSize; i++)
1111 {
1112 if (unionArray[i] != rightUnionArray[i])
1113 {
1114 boolNodeFlag = true;
1115 break; // break out of for loop
1116 }
1117 }
1118 }
1119
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001120 tempConstArray = new TConstantUnion[1];
Jamie Madillb1a85f42014-08-19 15:23:24 -04001121 if (!boolNodeFlag)
1122 {
1123 tempConstArray->setBConst(true);
1124 }
1125 else
1126 {
1127 tempConstArray->setBConst(false);
1128 }
1129
1130 tempNode = new TIntermConstantUnion(
1131 tempConstArray, TType(EbtBool, EbpUndefined, EvqConst));
1132 tempNode->setLine(getLine());
1133
1134 return tempNode;
1135
1136 case EOpNotEqual:
1137 if (getType().getBasicType() == EbtStruct)
1138 {
Olli Etuaho2cb7b832015-04-23 20:27:44 +03001139 if (CompareStructure(rightNode->getType(),
1140 rightNode->getUnionArrayPointer(),
Jamie Madillb1a85f42014-08-19 15:23:24 -04001141 unionArray))
1142 {
1143 boolNodeFlag = true;
1144 }
1145 }
1146 else
1147 {
1148 for (size_t i = 0; i < objectSize; i++)
1149 {
1150 if (unionArray[i] == rightUnionArray[i])
1151 {
1152 boolNodeFlag = true;
1153 break; // break out of for loop
1154 }
1155 }
1156 }
1157
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001158 tempConstArray = new TConstantUnion[1];
Jamie Madillb1a85f42014-08-19 15:23:24 -04001159 if (!boolNodeFlag)
1160 {
1161 tempConstArray->setBConst(true);
1162 }
1163 else
1164 {
1165 tempConstArray->setBConst(false);
1166 }
1167
1168 tempNode = new TIntermConstantUnion(
1169 tempConstArray, TType(EbtBool, EbpUndefined, EvqConst));
1170 tempNode->setLine(getLine());
1171
1172 return tempNode;
1173
1174 default:
1175 infoSink.info.message(
1176 EPrefixInternalError, getLine(),
1177 "Invalid operator for constant folding");
Arun Patolefddc2112015-04-22 13:28:10 +05301178 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001179 }
1180 tempNode = new TIntermConstantUnion(tempConstArray, returnType);
1181 tempNode->setLine(getLine());
1182
1183 return tempNode;
1184 }
Arun Patole2decb4b2015-05-25 19:20:26 +05301185 else if (op == EOpAny || op == EOpAll || op == EOpLength)
Arun Patole9d0b1f92015-05-20 14:27:17 +05301186 {
1187 // Do operations where the return type is different from the operand type.
1188
Arun Patole2decb4b2015-05-25 19:20:26 +05301189 TType returnType;
Arun Patole9d0b1f92015-05-20 14:27:17 +05301190 TConstantUnion *tempConstArray = nullptr;
Arun Patole2decb4b2015-05-25 19:20:26 +05301191 switch (op)
Arun Patole9d0b1f92015-05-20 14:27:17 +05301192 {
Arun Patole2decb4b2015-05-25 19:20:26 +05301193 case EOpAny:
Arun Patole9d0b1f92015-05-20 14:27:17 +05301194 if (getType().getBasicType() == EbtBool)
1195 {
1196 tempConstArray = new TConstantUnion();
1197 tempConstArray->setBConst(false);
1198 for (size_t i = 0; i < objectSize; i++)
1199 {
1200 if (unionArray[i].getBConst())
1201 {
1202 tempConstArray->setBConst(true);
1203 break;
1204 }
1205 }
Arun Patole2decb4b2015-05-25 19:20:26 +05301206 returnType = TType(EbtBool, EbpUndefined, EvqConst);
1207 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05301208 }
1209 else
1210 {
Arun Patole2decb4b2015-05-25 19:20:26 +05301211 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
Arun Patole9d0b1f92015-05-20 14:27:17 +05301212 return nullptr;
1213 }
Arun Patole2decb4b2015-05-25 19:20:26 +05301214
1215 case EOpAll:
Arun Patole9d0b1f92015-05-20 14:27:17 +05301216 if (getType().getBasicType() == EbtBool)
1217 {
1218 tempConstArray = new TConstantUnion();
1219 tempConstArray->setBConst(true);
1220 for (size_t i = 0; i < objectSize; i++)
1221 {
1222 if (!unionArray[i].getBConst())
1223 {
1224 tempConstArray->setBConst(false);
1225 break;
1226 }
1227 }
Arun Patole2decb4b2015-05-25 19:20:26 +05301228 returnType = TType(EbtBool, EbpUndefined, EvqConst);
1229 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05301230 }
1231 else
1232 {
Arun Patole2decb4b2015-05-25 19:20:26 +05301233 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
Arun Patole9d0b1f92015-05-20 14:27:17 +05301234 return nullptr;
1235 }
Arun Patole2decb4b2015-05-25 19:20:26 +05301236
1237 case EOpLength:
1238 if (getType().getBasicType() == EbtFloat)
1239 {
1240 tempConstArray = new TConstantUnion();
1241 tempConstArray->setFConst(VectorLength(unionArray, objectSize));
1242 returnType = TType(EbtFloat, getType().getPrecision(), EvqConst);
1243 break;
1244 }
1245 else
1246 {
1247 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1248 return nullptr;
1249 }
1250
1251 default:
1252 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05301253 }
Arun Patole2decb4b2015-05-25 19:20:26 +05301254
Arun Patole9d0b1f92015-05-20 14:27:17 +05301255 TIntermConstantUnion *tempNode = new TIntermConstantUnion(tempConstArray, returnType);
1256 tempNode->setLine(getLine());
1257 return tempNode;
1258 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04001259 else
1260 {
1261 //
Arun Patole9d0b1f92015-05-20 14:27:17 +05301262 // Do unary operations where the return type is the same as operand type.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001263 //
1264 TIntermConstantUnion *newNode = 0;
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001265 TConstantUnion* tempConstArray = new TConstantUnion[objectSize];
Jamie Madillb1a85f42014-08-19 15:23:24 -04001266 for (size_t i = 0; i < objectSize; i++)
1267 {
1268 switch(op)
1269 {
1270 case EOpNegative:
1271 switch (getType().getBasicType())
1272 {
1273 case EbtFloat:
1274 tempConstArray[i].setFConst(-unionArray[i].getFConst());
1275 break;
1276 case EbtInt:
1277 tempConstArray[i].setIConst(-unionArray[i].getIConst());
1278 break;
1279 case EbtUInt:
1280 tempConstArray[i].setUConst(static_cast<unsigned int>(
1281 -static_cast<int>(unionArray[i].getUConst())));
1282 break;
1283 default:
1284 infoSink.info.message(
1285 EPrefixInternalError, getLine(),
1286 "Unary operation not folded into constant");
Arun Patolefddc2112015-04-22 13:28:10 +05301287 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001288 }
1289 break;
1290
Zhenyao Mode1e00e2014-10-09 16:55:32 -07001291 case EOpPositive:
1292 switch (getType().getBasicType())
1293 {
1294 case EbtFloat:
1295 tempConstArray[i].setFConst(unionArray[i].getFConst());
1296 break;
1297 case EbtInt:
1298 tempConstArray[i].setIConst(unionArray[i].getIConst());
1299 break;
1300 case EbtUInt:
1301 tempConstArray[i].setUConst(static_cast<unsigned int>(
1302 static_cast<int>(unionArray[i].getUConst())));
1303 break;
1304 default:
1305 infoSink.info.message(
1306 EPrefixInternalError, getLine(),
1307 "Unary operation not folded into constant");
Arun Patolefddc2112015-04-22 13:28:10 +05301308 return nullptr;
Zhenyao Mode1e00e2014-10-09 16:55:32 -07001309 }
1310 break;
1311
Jamie Madillb1a85f42014-08-19 15:23:24 -04001312 case EOpLogicalNot:
1313 // this code is written for possible future use,
1314 // will not get executed currently
1315 switch (getType().getBasicType())
1316 {
1317 case EbtBool:
1318 tempConstArray[i].setBConst(!unionArray[i].getBConst());
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;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001325 }
1326 break;
1327
Olli Etuaho31b5fc62015-01-16 12:13:36 +02001328 case EOpBitwiseNot:
1329 switch (getType().getBasicType())
1330 {
1331 case EbtInt:
1332 tempConstArray[i].setIConst(~unionArray[i].getIConst());
1333 break;
1334 case EbtUInt:
1335 tempConstArray[i].setUConst(~unionArray[i].getUConst());
1336 break;
1337 default:
1338 infoSink.info.message(
1339 EPrefixInternalError, getLine(),
1340 "Unary operation not folded into constant");
Arun Patolefddc2112015-04-22 13:28:10 +05301341 return nullptr;
Olli Etuaho31b5fc62015-01-16 12:13:36 +02001342 }
1343 break;
1344
Arun Patole9dea48f2015-04-02 11:45:09 +05301345 case EOpRadians:
1346 if (getType().getBasicType() == EbtFloat)
1347 {
1348 tempConstArray[i].setFConst(kDegreesToRadiansMultiplier * unionArray[i].getFConst());
1349 break;
1350 }
1351 infoSink.info.message(
1352 EPrefixInternalError, getLine(),
1353 "Unary operation not folded into constant");
1354 return nullptr;
1355
1356 case EOpDegrees:
1357 if (getType().getBasicType() == EbtFloat)
1358 {
1359 tempConstArray[i].setFConst(kRadiansToDegreesMultiplier * unionArray[i].getFConst());
1360 break;
1361 }
1362 infoSink.info.message(
1363 EPrefixInternalError, getLine(),
1364 "Unary operation not folded into constant");
1365 return nullptr;
1366
1367 case EOpSin:
1368 if (!foldFloatTypeUnary(unionArray[i], &sinf, infoSink, &tempConstArray[i]))
1369 return nullptr;
1370 break;
1371
1372 case EOpCos:
1373 if (!foldFloatTypeUnary(unionArray[i], &cosf, infoSink, &tempConstArray[i]))
1374 return nullptr;
1375 break;
1376
1377 case EOpTan:
1378 if (!foldFloatTypeUnary(unionArray[i], &tanf, infoSink, &tempConstArray[i]))
1379 return nullptr;
1380 break;
1381
1382 case EOpAsin:
1383 // For asin(x), results are undefined if |x| > 1, we are choosing to set result to 0.
1384 if (getType().getBasicType() == EbtFloat && fabsf(unionArray[i].getFConst()) > 1.0f)
Arun Patole081c3f22015-05-25 15:43:35 +05301385 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &tempConstArray[i]);
Arun Patole9dea48f2015-04-02 11:45:09 +05301386 else if (!foldFloatTypeUnary(unionArray[i], &asinf, infoSink, &tempConstArray[i]))
1387 return nullptr;
1388 break;
1389
1390 case EOpAcos:
1391 // For acos(x), results are undefined if |x| > 1, we are choosing to set result to 0.
1392 if (getType().getBasicType() == EbtFloat && fabsf(unionArray[i].getFConst()) > 1.0f)
Arun Patole081c3f22015-05-25 15:43:35 +05301393 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &tempConstArray[i]);
Arun Patole9dea48f2015-04-02 11:45:09 +05301394 else if (!foldFloatTypeUnary(unionArray[i], &acosf, infoSink, &tempConstArray[i]))
1395 return nullptr;
1396 break;
1397
1398 case EOpAtan:
1399 if (!foldFloatTypeUnary(unionArray[i], &atanf, infoSink, &tempConstArray[i]))
1400 return nullptr;
1401 break;
1402
1403 case EOpSinh:
1404 if (!foldFloatTypeUnary(unionArray[i], &sinhf, infoSink, &tempConstArray[i]))
1405 return nullptr;
1406 break;
1407
1408 case EOpCosh:
1409 if (!foldFloatTypeUnary(unionArray[i], &coshf, infoSink, &tempConstArray[i]))
1410 return nullptr;
1411 break;
1412
1413 case EOpTanh:
1414 if (!foldFloatTypeUnary(unionArray[i], &tanhf, infoSink, &tempConstArray[i]))
1415 return nullptr;
1416 break;
1417
1418 case EOpAsinh:
1419 if (!foldFloatTypeUnary(unionArray[i], &asinhf, infoSink, &tempConstArray[i]))
1420 return nullptr;
1421 break;
1422
1423 case EOpAcosh:
1424 // For acosh(x), results are undefined if x < 1, we are choosing to set result to 0.
1425 if (getType().getBasicType() == EbtFloat && unionArray[i].getFConst() < 1.0f)
Arun Patole081c3f22015-05-25 15:43:35 +05301426 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &tempConstArray[i]);
Arun Patole9dea48f2015-04-02 11:45:09 +05301427 else if (!foldFloatTypeUnary(unionArray[i], &acoshf, infoSink, &tempConstArray[i]))
1428 return nullptr;
1429 break;
1430
1431 case EOpAtanh:
1432 // For atanh(x), results are undefined if |x| >= 1, we are choosing to set result to 0.
1433 if (getType().getBasicType() == EbtFloat && fabsf(unionArray[i].getFConst()) >= 1.0f)
Arun Patole081c3f22015-05-25 15:43:35 +05301434 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &tempConstArray[i]);
Arun Patole9dea48f2015-04-02 11:45:09 +05301435 else if (!foldFloatTypeUnary(unionArray[i], &atanhf, infoSink, &tempConstArray[i]))
1436 return nullptr;
1437 break;
1438
Arun Patole97dc22e2015-04-06 17:35:38 +05301439 case EOpAbs:
1440 switch (getType().getBasicType())
1441 {
1442 case EbtFloat:
1443 tempConstArray[i].setFConst(fabsf(unionArray[i].getFConst()));
1444 break;
1445 case EbtInt:
1446 tempConstArray[i].setIConst(abs(unionArray[i].getIConst()));
1447 break;
1448 default:
1449 infoSink.info.message(
1450 EPrefixInternalError, getLine(),
1451 "Unary operation not folded into constant");
1452 return nullptr;
1453 }
1454 break;
1455
1456 case EOpSign:
1457 switch (getType().getBasicType())
1458 {
1459 case EbtFloat:
1460 {
1461 float fConst = unionArray[i].getFConst();
1462 float fResult = 0.0f;
1463 if (fConst > 0.0f)
1464 fResult = 1.0f;
1465 else if (fConst < 0.0f)
1466 fResult = -1.0f;
1467 tempConstArray[i].setFConst(fResult);
1468 }
1469 break;
1470 case EbtInt:
1471 {
1472 int iConst = unionArray[i].getIConst();
1473 int iResult = 0;
1474 if (iConst > 0)
1475 iResult = 1;
1476 else if (iConst < 0)
1477 iResult = -1;
1478 tempConstArray[i].setIConst(iResult);
1479 }
1480 break;
1481 default:
1482 infoSink.info.message(
1483 EPrefixInternalError, getLine(),
1484 "Unary operation not folded into constant");
1485 return nullptr;
1486 }
1487 break;
1488
1489 case EOpFloor:
1490 if (!foldFloatTypeUnary(unionArray[i], &floorf, infoSink, &tempConstArray[i]))
1491 return nullptr;
1492 break;
1493
1494 case EOpTrunc:
1495 if (!foldFloatTypeUnary(unionArray[i], &truncf, infoSink, &tempConstArray[i]))
1496 return nullptr;
1497 break;
1498
1499 case EOpRound:
1500 if (!foldFloatTypeUnary(unionArray[i], &roundf, infoSink, &tempConstArray[i]))
1501 return nullptr;
1502 break;
1503
1504 case EOpRoundEven:
1505 if (getType().getBasicType() == EbtFloat)
1506 {
1507 float x = unionArray[i].getFConst();
1508 float result;
1509 float fractPart = modff(x, &result);
1510 if (fabsf(fractPart) == 0.5f)
1511 result = 2.0f * roundf(x / 2.0f);
1512 else
1513 result = roundf(x);
1514 tempConstArray[i].setFConst(result);
1515 break;
1516 }
1517 infoSink.info.message(
1518 EPrefixInternalError, getLine(),
1519 "Unary operation not folded into constant");
1520 return nullptr;
1521
1522 case EOpCeil:
1523 if (!foldFloatTypeUnary(unionArray[i], &ceilf, infoSink, &tempConstArray[i]))
1524 return nullptr;
1525 break;
1526
1527 case EOpFract:
1528 if (getType().getBasicType() == EbtFloat)
1529 {
1530 float x = unionArray[i].getFConst();
1531 tempConstArray[i].setFConst(x - floorf(x));
1532 break;
1533 }
1534 infoSink.info.message(
1535 EPrefixInternalError, getLine(),
1536 "Unary operation not folded into constant");
1537 return nullptr;
1538
Arun Patole28eb65e2015-04-06 17:29:48 +05301539 case EOpExp:
1540 if (!foldFloatTypeUnary(unionArray[i], &expf, infoSink, &tempConstArray[i]))
1541 return nullptr;
1542 break;
1543
1544 case EOpLog:
1545 // For log(x), results are undefined if x <= 0, we are choosing to set result to 0.
1546 if (getType().getBasicType() == EbtFloat && unionArray[i].getFConst() <= 0.0f)
Arun Patole081c3f22015-05-25 15:43:35 +05301547 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &tempConstArray[i]);
Arun Patole28eb65e2015-04-06 17:29:48 +05301548 else if (!foldFloatTypeUnary(unionArray[i], &logf, infoSink, &tempConstArray[i]))
1549 return nullptr;
1550 break;
1551
1552 case EOpExp2:
1553 if (!foldFloatTypeUnary(unionArray[i], &exp2f, infoSink, &tempConstArray[i]))
1554 return nullptr;
1555 break;
1556
1557 case EOpLog2:
1558 // For log2(x), results are undefined if x <= 0, we are choosing to set result to 0.
1559 // And log2f is not available on some plarforms like old android, so just using log(x)/log(2) here.
1560 if (getType().getBasicType() == EbtFloat && unionArray[i].getFConst() <= 0.0f)
Arun Patole081c3f22015-05-25 15:43:35 +05301561 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &tempConstArray[i]);
Arun Patole28eb65e2015-04-06 17:29:48 +05301562 else if (!foldFloatTypeUnary(unionArray[i], &logf, infoSink, &tempConstArray[i]))
1563 return nullptr;
1564 else
1565 tempConstArray[i].setFConst(tempConstArray[i].getFConst() / logf(2.0f));
1566 break;
1567
1568 case EOpSqrt:
1569 // For sqrt(x), results are undefined if x < 0, we are choosing to set result to 0.
1570 if (getType().getBasicType() == EbtFloat && unionArray[i].getFConst() < 0.0f)
Arun Patole081c3f22015-05-25 15:43:35 +05301571 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &tempConstArray[i]);
Arun Patole28eb65e2015-04-06 17:29:48 +05301572 else if (!foldFloatTypeUnary(unionArray[i], &sqrtf, infoSink, &tempConstArray[i]))
1573 return nullptr;
1574 break;
1575
1576 case EOpInverseSqrt:
1577 // There is no stdlib built-in function equavalent for GLES built-in inversesqrt(),
1578 // so getting the square root first using builtin function sqrt() and then taking its inverse.
1579 // Also, for inversesqrt(x), results are undefined if x <= 0, we are choosing to set result to 0.
1580 if (getType().getBasicType() == EbtFloat && unionArray[i].getFConst() <= 0.0f)
Arun Patole081c3f22015-05-25 15:43:35 +05301581 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &tempConstArray[i]);
Arun Patole28eb65e2015-04-06 17:29:48 +05301582 else if (!foldFloatTypeUnary(unionArray[i], &sqrtf, infoSink, &tempConstArray[i]))
1583 return nullptr;
1584 else
1585 tempConstArray[i].setFConst(1.0f / tempConstArray[i].getFConst());
1586 break;
1587
Arun Patole9d0b1f92015-05-20 14:27:17 +05301588 case EOpVectorLogicalNot:
1589 if (getType().getBasicType() == EbtBool)
1590 {
1591 tempConstArray[i].setBConst(!unionArray[i].getBConst());
1592 break;
1593 }
1594 infoSink.info.message(
1595 EPrefixInternalError, getLine(),
1596 "Unary operation not folded into constant");
1597 return nullptr;
1598
Arun Patole2decb4b2015-05-25 19:20:26 +05301599 case EOpNormalize:
1600 if (getType().getBasicType() == EbtFloat)
1601 {
1602 float x = unionArray[i].getFConst();
1603 float length = VectorLength(unionArray, objectSize);
1604 if (length)
1605 tempConstArray[i].setFConst(x / length);
1606 else
1607 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &tempConstArray[i]);
1608 break;
1609 }
1610 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1611 return nullptr;
1612
Jamie Madillb1a85f42014-08-19 15:23:24 -04001613 default:
Arun Patolefddc2112015-04-22 13:28:10 +05301614 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001615 }
1616 }
1617 newNode = new TIntermConstantUnion(tempConstArray, getType());
1618 newNode->setLine(getLine());
1619 return newNode;
1620 }
1621}
1622
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001623bool TIntermConstantUnion::foldFloatTypeUnary(const TConstantUnion &parameter, FloatTypeUnaryFunc builtinFunc,
1624 TInfoSink &infoSink, TConstantUnion *result) const
Arun Patole9dea48f2015-04-02 11:45:09 +05301625{
1626 ASSERT(builtinFunc);
1627
1628 if (getType().getBasicType() == EbtFloat)
1629 {
1630 result->setFConst(builtinFunc(parameter.getFConst()));
1631 return true;
1632 }
1633
1634 infoSink.info.message(
1635 EPrefixInternalError, getLine(),
1636 "Unary operation not folded into constant");
1637 return false;
1638}
1639
Jamie Madillb1a85f42014-08-19 15:23:24 -04001640// static
Arun Patolebf790422015-05-18 17:53:04 +05301641TIntermTyped *TIntermConstantUnion::FoldAggregateBuiltIn(TOperator op, TIntermAggregate *aggregate, TInfoSink &infoSink)
Arun Patole274f0702015-05-05 13:33:30 +05301642{
1643 TIntermSequence *sequence = aggregate->getSequence();
1644 unsigned int paramsCount = sequence->size();
1645 std::vector<TConstantUnion *> unionArrays(paramsCount);
1646 std::vector<size_t> objectSizes(paramsCount);
1647 TType *maxSizeType = nullptr;
1648 TBasicType basicType = EbtVoid;
1649 TSourceLoc loc;
1650 for (unsigned int i = 0; i < paramsCount; i++)
1651 {
1652 TIntermConstantUnion *paramConstant = (*sequence)[i]->getAsConstantUnion();
1653 // Make sure that all params are constant before actual constant folding.
1654 if (!paramConstant)
1655 return nullptr;
1656
1657 if (i == 0)
1658 {
1659 basicType = paramConstant->getType().getBasicType();
1660 loc = paramConstant->getLine();
1661 }
1662 unionArrays[i] = paramConstant->getUnionArrayPointer();
1663 objectSizes[i] = paramConstant->getType().getObjectSize();
1664 if (maxSizeType == nullptr || (objectSizes[i] >= maxSizeType->getObjectSize()))
1665 maxSizeType = paramConstant->getTypePointer();
1666 }
1667
1668 size_t maxObjectSize = maxSizeType->getObjectSize();
1669 for (unsigned int i = 0; i < paramsCount; i++)
1670 if (objectSizes[i] != maxObjectSize)
1671 unionArrays[i] = Vectorize(*unionArrays[i], maxObjectSize);
1672
1673 TConstantUnion *tempConstArray = nullptr;
1674 TIntermConstantUnion *tempNode = nullptr;
1675 TType returnType = *maxSizeType;
1676 if (paramsCount == 2)
1677 {
1678 //
1679 // Binary built-in
1680 //
1681 switch (op)
1682 {
Arun Patolebf790422015-05-18 17:53:04 +05301683 case EOpAtan:
1684 {
1685 if (basicType == EbtFloat)
1686 {
1687 tempConstArray = new TConstantUnion[maxObjectSize];
1688 for (size_t i = 0; i < maxObjectSize; i++)
1689 {
1690 float y = unionArrays[0][i].getFConst();
1691 float x = unionArrays[1][i].getFConst();
1692 // Results are undefined if x and y are both 0.
1693 if (x == 0.0f && y == 0.0f)
1694 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &tempConstArray[i]);
1695 else
1696 tempConstArray[i].setFConst(atan2f(y, x));
1697 }
1698 }
1699 else
1700 UNREACHABLE();
1701 }
1702 break;
1703
1704 case EOpPow:
1705 {
1706 if (basicType == EbtFloat)
1707 {
1708 tempConstArray = new TConstantUnion[maxObjectSize];
1709 for (size_t i = 0; i < maxObjectSize; i++)
1710 {
1711 float x = unionArrays[0][i].getFConst();
1712 float y = unionArrays[1][i].getFConst();
1713 // Results are undefined if x < 0.
1714 // Results are undefined if x = 0 and y <= 0.
1715 if (x < 0.0f)
1716 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &tempConstArray[i]);
1717 else if (x == 0.0f && y <= 0.0f)
1718 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &tempConstArray[i]);
1719 else
1720 tempConstArray[i].setFConst(powf(x, y));
1721 }
1722 }
1723 else
1724 UNREACHABLE();
1725 }
1726 break;
1727
1728 case EOpMod:
1729 {
1730 if (basicType == EbtFloat)
1731 {
1732 tempConstArray = new TConstantUnion[maxObjectSize];
1733 for (size_t i = 0; i < maxObjectSize; i++)
1734 {
1735 float x = unionArrays[0][i].getFConst();
1736 float y = unionArrays[1][i].getFConst();
1737 tempConstArray[i].setFConst(x - y * floorf(x / y));
1738 }
1739 }
1740 else
1741 UNREACHABLE();
1742 }
1743 break;
1744
Arun Patole274f0702015-05-05 13:33:30 +05301745 case EOpMin:
1746 {
1747 tempConstArray = new TConstantUnion[maxObjectSize];
1748 for (size_t i = 0; i < maxObjectSize; i++)
1749 {
1750 switch (basicType)
1751 {
1752 case EbtFloat:
1753 tempConstArray[i].setFConst(std::min(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
1754 break;
1755 case EbtInt:
1756 tempConstArray[i].setIConst(std::min(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
1757 break;
1758 case EbtUInt:
1759 tempConstArray[i].setUConst(std::min(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
1760 break;
1761 default:
1762 UNREACHABLE();
1763 break;
1764 }
1765 }
1766 }
1767 break;
1768
1769 case EOpMax:
1770 {
1771 tempConstArray = new TConstantUnion[maxObjectSize];
1772 for (size_t i = 0; i < maxObjectSize; i++)
1773 {
1774 switch (basicType)
1775 {
1776 case EbtFloat:
1777 tempConstArray[i].setFConst(std::max(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
1778 break;
1779 case EbtInt:
1780 tempConstArray[i].setIConst(std::max(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
1781 break;
1782 case EbtUInt:
1783 tempConstArray[i].setUConst(std::max(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
1784 break;
1785 default:
1786 UNREACHABLE();
1787 break;
1788 }
1789 }
1790 }
1791 break;
1792
Arun Patolebf790422015-05-18 17:53:04 +05301793 case EOpStep:
1794 {
1795 if (basicType == EbtFloat)
1796 {
1797 tempConstArray = new TConstantUnion[maxObjectSize];
1798 for (size_t i = 0; i < maxObjectSize; i++)
1799 tempConstArray[i].setFConst(unionArrays[1][i].getFConst() < unionArrays[0][i].getFConst() ? 0.0f : 1.0f);
1800 }
1801 else
1802 UNREACHABLE();
1803 }
1804 break;
1805
Arun Patole9d0b1f92015-05-20 14:27:17 +05301806 case EOpLessThan:
1807 {
1808 tempConstArray = new TConstantUnion[maxObjectSize];
1809 for (size_t i = 0; i < maxObjectSize; i++)
1810 {
1811 switch (basicType)
1812 {
1813 case EbtFloat:
1814 tempConstArray[i].setBConst(unionArrays[0][i].getFConst() < unionArrays[1][i].getFConst());
1815 break;
1816 case EbtInt:
1817 tempConstArray[i].setBConst(unionArrays[0][i].getIConst() < unionArrays[1][i].getIConst());
1818 break;
1819 case EbtUInt:
1820 tempConstArray[i].setBConst(unionArrays[0][i].getUConst() < unionArrays[1][i].getUConst());
1821 break;
1822 default:
1823 UNREACHABLE();
1824 break;
1825 }
1826 }
1827 }
1828 break;
1829
1830 case EOpLessThanEqual:
1831 {
1832 tempConstArray = new TConstantUnion[maxObjectSize];
1833 for (size_t i = 0; i < maxObjectSize; i++)
1834 {
1835 switch (basicType)
1836 {
1837 case EbtFloat:
1838 tempConstArray[i].setBConst(unionArrays[0][i].getFConst() <= unionArrays[1][i].getFConst());
1839 break;
1840 case EbtInt:
1841 tempConstArray[i].setBConst(unionArrays[0][i].getIConst() <= unionArrays[1][i].getIConst());
1842 break;
1843 case EbtUInt:
1844 tempConstArray[i].setBConst(unionArrays[0][i].getUConst() <= unionArrays[1][i].getUConst());
1845 break;
1846 default:
1847 UNREACHABLE();
1848 break;
1849 }
1850 }
1851 }
1852 break;
1853
1854 case EOpGreaterThan:
1855 {
1856 tempConstArray = new TConstantUnion[maxObjectSize];
1857 for (size_t i = 0; i < maxObjectSize; i++)
1858 {
1859 switch (basicType)
1860 {
1861 case EbtFloat:
1862 tempConstArray[i].setBConst(unionArrays[0][i].getFConst() > unionArrays[1][i].getFConst());
1863 break;
1864 case EbtInt:
1865 tempConstArray[i].setBConst(unionArrays[0][i].getIConst() > unionArrays[1][i].getIConst());
1866 break;
1867 case EbtUInt:
1868 tempConstArray[i].setBConst(unionArrays[0][i].getUConst() > unionArrays[1][i].getUConst());
1869 break;
1870 default:
1871 UNREACHABLE();
1872 break;
1873 }
1874 }
1875 }
1876 break;
1877
1878 case EOpGreaterThanEqual:
1879 {
1880 tempConstArray = new TConstantUnion[maxObjectSize];
1881 for (size_t i = 0; i < maxObjectSize; i++)
1882 {
1883 switch (basicType)
1884 {
1885 case EbtFloat:
1886 tempConstArray[i].setBConst(unionArrays[0][i].getFConst() >= unionArrays[1][i].getFConst());
1887 break;
1888 case EbtInt:
1889 tempConstArray[i].setBConst(unionArrays[0][i].getIConst() >= unionArrays[1][i].getIConst());
1890 break;
1891 case EbtUInt:
1892 tempConstArray[i].setBConst(unionArrays[0][i].getUConst() >= unionArrays[1][i].getUConst());
1893 break;
1894 default:
1895 UNREACHABLE();
1896 break;
1897 }
1898 }
1899 }
1900 break;
1901
1902 case EOpVectorEqual:
1903 {
1904 tempConstArray = new TConstantUnion[maxObjectSize];
1905 for (size_t i = 0; i < maxObjectSize; i++)
1906 {
1907 switch (basicType)
1908 {
1909 case EbtFloat:
1910 tempConstArray[i].setBConst(unionArrays[0][i].getFConst() == unionArrays[1][i].getFConst());
1911 break;
1912 case EbtInt:
1913 tempConstArray[i].setBConst(unionArrays[0][i].getIConst() == unionArrays[1][i].getIConst());
1914 break;
1915 case EbtUInt:
1916 tempConstArray[i].setBConst(unionArrays[0][i].getUConst() == unionArrays[1][i].getUConst());
1917 break;
1918 case EbtBool:
1919 tempConstArray[i].setBConst(unionArrays[0][i].getBConst() == unionArrays[1][i].getBConst());
1920 break;
1921 default:
1922 UNREACHABLE();
1923 break;
1924 }
1925 }
1926 }
1927 break;
1928
1929 case EOpVectorNotEqual:
1930 {
1931 tempConstArray = new TConstantUnion[maxObjectSize];
1932 for (size_t i = 0; i < maxObjectSize; i++)
1933 {
1934 switch (basicType)
1935 {
1936 case EbtFloat:
1937 tempConstArray[i].setBConst(unionArrays[0][i].getFConst() != unionArrays[1][i].getFConst());
1938 break;
1939 case EbtInt:
1940 tempConstArray[i].setBConst(unionArrays[0][i].getIConst() != unionArrays[1][i].getIConst());
1941 break;
1942 case EbtUInt:
1943 tempConstArray[i].setBConst(unionArrays[0][i].getUConst() != unionArrays[1][i].getUConst());
1944 break;
1945 case EbtBool:
1946 tempConstArray[i].setBConst(unionArrays[0][i].getBConst() != unionArrays[1][i].getBConst());
1947 break;
1948 default:
1949 UNREACHABLE();
1950 break;
1951 }
1952 }
1953 }
1954 break;
1955
Arun Patole2decb4b2015-05-25 19:20:26 +05301956 case EOpDistance:
1957 if (basicType == EbtFloat)
1958 {
1959 TConstantUnion *distanceArray = new TConstantUnion[maxObjectSize];
1960 tempConstArray = new TConstantUnion();
1961 for (size_t i = 0; i < maxObjectSize; i++)
1962 {
1963 float x = unionArrays[0][i].getFConst();
1964 float y = unionArrays[1][i].getFConst();
1965 distanceArray[i].setFConst(x - y);
1966 }
1967 tempConstArray->setFConst(VectorLength(distanceArray, maxObjectSize));
1968 }
1969 else
1970 UNREACHABLE();
1971 break;
1972
1973 case EOpDot:
1974 if (basicType == EbtFloat)
1975 {
1976 tempConstArray = new TConstantUnion();
1977 tempConstArray->setFConst(VectorDotProduct(unionArrays[0], unionArrays[1], maxObjectSize));
1978 }
1979 else
1980 UNREACHABLE();
1981 break;
1982
1983 case EOpCross:
1984 if (basicType == EbtFloat && maxObjectSize == 3)
1985 {
1986 tempConstArray = new TConstantUnion[maxObjectSize];
1987 float x0 = unionArrays[0][0].getFConst();
1988 float x1 = unionArrays[0][1].getFConst();
1989 float x2 = unionArrays[0][2].getFConst();
1990 float y0 = unionArrays[1][0].getFConst();
1991 float y1 = unionArrays[1][1].getFConst();
1992 float y2 = unionArrays[1][2].getFConst();
1993 tempConstArray[0].setFConst(x1 * y2 - y1 * x2);
1994 tempConstArray[1].setFConst(x2 * y0 - y2 * x0);
1995 tempConstArray[2].setFConst(x0 * y1 - y0 * x1);
1996 }
1997 else
1998 UNREACHABLE();
1999 break;
2000
2001 case EOpReflect:
2002 if (basicType == EbtFloat)
2003 {
2004 // genType reflect (genType I, genType N) :
2005 // For the incident vector I and surface orientation N, returns the reflection direction:
2006 // I - 2 * dot(N, I) * N.
2007 tempConstArray = new TConstantUnion[maxObjectSize];
2008 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
2009 for (size_t i = 0; i < maxObjectSize; i++)
2010 {
2011 float result = unionArrays[0][i].getFConst() -
2012 2.0f * dotProduct * unionArrays[1][i].getFConst();
2013 tempConstArray[i].setFConst(result);
2014 }
2015 }
2016 else
2017 UNREACHABLE();
2018 break;
2019
Arun Patole274f0702015-05-05 13:33:30 +05302020 default:
2021 UNREACHABLE();
2022 // TODO: Add constant folding support for other built-in operations that take 2 parameters and not handled above.
2023 return nullptr;
2024 }
2025 }
2026 else if (paramsCount == 3)
2027 {
2028 //
2029 // Ternary built-in
2030 //
2031 switch (op)
2032 {
2033 case EOpClamp:
2034 {
2035 tempConstArray = new TConstantUnion[maxObjectSize];
2036 for (size_t i = 0; i < maxObjectSize; i++)
2037 {
2038 switch (basicType)
2039 {
2040 case EbtFloat:
2041 {
2042 float x = unionArrays[0][i].getFConst();
2043 float min = unionArrays[1][i].getFConst();
2044 float max = unionArrays[2][i].getFConst();
2045 // Results are undefined if min > max.
2046 if (min > max)
Arun Patole081c3f22015-05-25 15:43:35 +05302047 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &tempConstArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302048 else
2049 tempConstArray[i].setFConst(gl::clamp(x, min, max));
2050 }
2051 break;
2052 case EbtInt:
2053 {
2054 int x = unionArrays[0][i].getIConst();
2055 int min = unionArrays[1][i].getIConst();
2056 int max = unionArrays[2][i].getIConst();
2057 // Results are undefined if min > max.
2058 if (min > max)
Arun Patole081c3f22015-05-25 15:43:35 +05302059 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &tempConstArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302060 else
2061 tempConstArray[i].setIConst(gl::clamp(x, min, max));
2062 }
2063 break;
2064 case EbtUInt:
2065 {
2066 unsigned int x = unionArrays[0][i].getUConst();
2067 unsigned int min = unionArrays[1][i].getUConst();
2068 unsigned int max = unionArrays[2][i].getUConst();
2069 // Results are undefined if min > max.
2070 if (min > max)
Arun Patole081c3f22015-05-25 15:43:35 +05302071 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &tempConstArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302072 else
2073 tempConstArray[i].setUConst(gl::clamp(x, min, max));
2074 }
2075 break;
2076 default:
2077 UNREACHABLE();
2078 break;
2079 }
2080 }
2081 }
2082 break;
2083
Arun Patolebf790422015-05-18 17:53:04 +05302084 case EOpMix:
2085 {
2086 if (basicType == EbtFloat)
2087 {
2088 tempConstArray = new TConstantUnion[maxObjectSize];
2089 for (size_t i = 0; i < maxObjectSize; i++)
2090 {
2091 float x = unionArrays[0][i].getFConst();
2092 float y = unionArrays[1][i].getFConst();
2093 TBasicType type = (*sequence)[2]->getAsTyped()->getType().getBasicType();
2094 if (type == EbtFloat)
2095 {
2096 // Returns the linear blend of x and y, i.e., x * (1 - a) + y * a.
2097 float a = unionArrays[2][i].getFConst();
2098 tempConstArray[i].setFConst(x * (1.0f - a) + y * a);
2099 }
2100 else // 3rd parameter is EbtBool
2101 {
2102 ASSERT(type == EbtBool);
2103 // Selects which vector each returned component comes from.
2104 // For a component of a that is false, the corresponding component of x is returned.
2105 // For a component of a that is true, the corresponding component of y is returned.
2106 bool a = unionArrays[2][i].getBConst();
2107 tempConstArray[i].setFConst(a ? y : x);
2108 }
2109 }
2110 }
2111 else
2112 UNREACHABLE();
2113 }
2114 break;
2115
2116 case EOpSmoothStep:
2117 {
2118 if (basicType == EbtFloat)
2119 {
2120 tempConstArray = new TConstantUnion[maxObjectSize];
2121 for (size_t i = 0; i < maxObjectSize; i++)
2122 {
2123 float edge0 = unionArrays[0][i].getFConst();
2124 float edge1 = unionArrays[1][i].getFConst();
2125 float x = unionArrays[2][i].getFConst();
2126 // Results are undefined if edge0 >= edge1.
2127 if (edge0 >= edge1)
2128 {
2129 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &tempConstArray[i]);
2130 }
2131 else
2132 {
2133 // Returns 0.0 if x <= edge0 and 1.0 if x >= edge1 and performs smooth
2134 // Hermite interpolation between 0 and 1 when edge0 < x < edge1.
2135 float t = gl::clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f);
2136 tempConstArray[i].setFConst(t * t * (3.0f - 2.0f * t));
2137 }
2138 }
2139 }
2140 else
2141 UNREACHABLE();
2142 }
2143 break;
2144
Arun Patole2decb4b2015-05-25 19:20:26 +05302145 case EOpFaceForward:
2146 if (basicType == EbtFloat)
2147 {
2148 // genType faceforward(genType N, genType I, genType Nref) :
2149 // If dot(Nref, I) < 0 return N, otherwise return -N.
2150 tempConstArray = new TConstantUnion[maxObjectSize];
2151 float dotProduct = VectorDotProduct(unionArrays[2], unionArrays[1], maxObjectSize);
2152 for (size_t i = 0; i < maxObjectSize; i++)
2153 {
2154 if (dotProduct < 0)
2155 tempConstArray[i].setFConst(unionArrays[0][i].getFConst());
2156 else
2157 tempConstArray[i].setFConst(-unionArrays[0][i].getFConst());
2158 }
2159 }
2160 else
2161 UNREACHABLE();
2162 break;
2163
2164 case EOpRefract:
2165 if (basicType == EbtFloat)
2166 {
2167 // genType refract(genType I, genType N, float eta) :
2168 // For the incident vector I and surface normal N, and the ratio of indices of refraction eta,
2169 // return the refraction vector. The result is computed by
2170 // k = 1.0 - eta * eta * (1.0 - dot(N, I) * dot(N, I))
2171 // if (k < 0.0)
2172 // return genType(0.0)
2173 // else
2174 // return eta * I - (eta * dot(N, I) + sqrt(k)) * N
2175 tempConstArray = new TConstantUnion[maxObjectSize];
2176 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
2177 for (size_t i = 0; i < maxObjectSize; i++)
2178 {
2179 float eta = unionArrays[2][i].getFConst();
2180 float k = 1.0f - eta * eta * (1.0f - dotProduct * dotProduct);
2181 if (k < 0.0f)
2182 tempConstArray[i].setFConst(0.0f);
2183 else
2184 tempConstArray[i].setFConst(eta * unionArrays[0][i].getFConst() -
2185 (eta * dotProduct + sqrtf(k)) * unionArrays[1][i].getFConst());
2186 }
2187 }
2188 else
2189 UNREACHABLE();
2190 break;
2191
Arun Patole274f0702015-05-05 13:33:30 +05302192 default:
2193 UNREACHABLE();
2194 // TODO: Add constant folding support for other built-in operations that take 3 parameters and not handled above.
2195 return nullptr;
2196 }
2197 }
2198
2199 if (tempConstArray)
2200 {
2201 tempNode = new TIntermConstantUnion(tempConstArray, returnType);
2202 tempNode->setLine(loc);
2203 }
2204 return tempNode;
2205}
2206
2207// static
Jamie Madillb1a85f42014-08-19 15:23:24 -04002208TString TIntermTraverser::hash(const TString &name, ShHashFunction64 hashFunction)
2209{
2210 if (hashFunction == NULL || name.empty())
2211 return name;
2212 khronos_uint64_t number = (*hashFunction)(name.c_str(), name.length());
2213 TStringStream stream;
2214 stream << HASHED_NAME_PREFIX << std::hex << number;
2215 TString hashedName = stream.str();
2216 return hashedName;
2217}
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002218
2219void TIntermTraverser::updateTree()
2220{
Olli Etuahoa6f22092015-05-08 18:31:10 +03002221 for (size_t ii = 0; ii < mInsertions.size(); ++ii)
2222 {
2223 const NodeInsertMultipleEntry &insertion = mInsertions[ii];
2224 ASSERT(insertion.parent);
2225 bool inserted = insertion.parent->insertChildNodes(insertion.position, insertion.insertions);
2226 ASSERT(inserted);
2227 UNUSED_ASSERTION_VARIABLE(inserted);
2228 }
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002229 for (size_t ii = 0; ii < mReplacements.size(); ++ii)
2230 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03002231 const NodeUpdateEntry &replacement = mReplacements[ii];
2232 ASSERT(replacement.parent);
2233 bool replaced = replacement.parent->replaceChildNode(
2234 replacement.original, replacement.replacement);
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002235 ASSERT(replaced);
Olli Etuahod57e0db2015-04-24 15:05:08 +03002236 UNUSED_ASSERTION_VARIABLE(replaced);
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002237
Olli Etuahocd94ef92015-04-16 19:18:10 +03002238 if (!replacement.originalBecomesChildOfReplacement)
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002239 {
2240 // In AST traversing, a parent is visited before its children.
Olli Etuahocd94ef92015-04-16 19:18:10 +03002241 // After we replace a node, if its immediate child is to
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002242 // be replaced, we need to make sure we don't update the replaced
2243 // node; instead, we update the replacement node.
2244 for (size_t jj = ii + 1; jj < mReplacements.size(); ++jj)
2245 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03002246 NodeUpdateEntry &replacement2 = mReplacements[jj];
2247 if (replacement2.parent == replacement.original)
2248 replacement2.parent = replacement.replacement;
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002249 }
2250 }
2251 }
Olli Etuahofc0e2bc2015-04-16 13:39:56 +03002252 for (size_t ii = 0; ii < mMultiReplacements.size(); ++ii)
2253 {
2254 const NodeReplaceWithMultipleEntry &replacement = mMultiReplacements[ii];
2255 ASSERT(replacement.parent);
2256 bool replaced = replacement.parent->replaceChildNodeWithMultiple(
2257 replacement.original, replacement.replacements);
2258 ASSERT(replaced);
Olli Etuahod57e0db2015-04-24 15:05:08 +03002259 UNUSED_ASSERTION_VARIABLE(replaced);
Olli Etuahofc0e2bc2015-04-16 13:39:56 +03002260 }
Olli Etuahod4f303e2015-05-20 17:09:06 +03002261
2262 mInsertions.clear();
2263 mReplacements.clear();
2264 mMultiReplacements.clear();
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002265}