blob: 2bff86c39992ce61235f2fcb4f6e1f69edfa0763 [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
Jamie Madillb1a85f42014-08-19 15:23:24 -0400171} // namespace anonymous
172
173
174////////////////////////////////////////////////////////////////
175//
176// Member functions of the nodes used for building the tree.
177//
178////////////////////////////////////////////////////////////////
179
Olli Etuahod2a67b92014-10-21 16:42:57 +0300180void TIntermTyped::setTypePreservePrecision(const TType &t)
181{
182 TPrecision precision = getPrecision();
183 mType = t;
184 ASSERT(mType.getBasicType() != EbtBool || precision == EbpUndefined);
185 mType.setPrecision(precision);
186}
187
Jamie Madillb1a85f42014-08-19 15:23:24 -0400188#define REPLACE_IF_IS(node, type, original, replacement) \
189 if (node == original) { \
190 node = static_cast<type *>(replacement); \
191 return true; \
192 }
193
194bool TIntermLoop::replaceChildNode(
195 TIntermNode *original, TIntermNode *replacement)
196{
197 REPLACE_IF_IS(mInit, TIntermNode, original, replacement);
198 REPLACE_IF_IS(mCond, TIntermTyped, original, replacement);
199 REPLACE_IF_IS(mExpr, TIntermTyped, original, replacement);
200 REPLACE_IF_IS(mBody, TIntermNode, original, replacement);
201 return false;
202}
203
Jamie Madillb1a85f42014-08-19 15:23:24 -0400204bool TIntermBranch::replaceChildNode(
205 TIntermNode *original, TIntermNode *replacement)
206{
207 REPLACE_IF_IS(mExpression, TIntermTyped, original, replacement);
208 return false;
209}
210
Jamie Madillb1a85f42014-08-19 15:23:24 -0400211bool TIntermBinary::replaceChildNode(
212 TIntermNode *original, TIntermNode *replacement)
213{
214 REPLACE_IF_IS(mLeft, TIntermTyped, original, replacement);
215 REPLACE_IF_IS(mRight, TIntermTyped, original, replacement);
216 return false;
217}
218
Jamie Madillb1a85f42014-08-19 15:23:24 -0400219bool TIntermUnary::replaceChildNode(
220 TIntermNode *original, TIntermNode *replacement)
221{
222 REPLACE_IF_IS(mOperand, TIntermTyped, original, replacement);
223 return false;
224}
225
Jamie Madillb1a85f42014-08-19 15:23:24 -0400226bool TIntermAggregate::replaceChildNode(
227 TIntermNode *original, TIntermNode *replacement)
228{
229 for (size_t ii = 0; ii < mSequence.size(); ++ii)
230 {
231 REPLACE_IF_IS(mSequence[ii], TIntermNode, original, replacement);
232 }
233 return false;
234}
235
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300236bool TIntermAggregate::replaceChildNodeWithMultiple(TIntermNode *original, TIntermSequence replacements)
237{
238 for (auto it = mSequence.begin(); it < mSequence.end(); ++it)
239 {
240 if (*it == original)
241 {
242 it = mSequence.erase(it);
Olli Etuaho8fee0ab2015-04-23 14:52:46 +0300243 mSequence.insert(it, replacements.begin(), replacements.end());
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300244 return true;
245 }
246 }
247 return false;
248}
249
Olli Etuahoa6f22092015-05-08 18:31:10 +0300250bool TIntermAggregate::insertChildNodes(TIntermSequence::size_type position, TIntermSequence insertions)
251{
252 TIntermSequence::size_type itPosition = 0;
253 for (auto it = mSequence.begin(); it < mSequence.end(); ++it)
254 {
255 if (itPosition == position)
256 {
257 mSequence.insert(it, insertions.begin(), insertions.end());
258 return true;
259 }
260 ++itPosition;
261 }
262 return false;
263}
264
Olli Etuahod2a67b92014-10-21 16:42:57 +0300265void TIntermAggregate::setPrecisionFromChildren()
266{
267 if (getBasicType() == EbtBool)
268 {
269 mType.setPrecision(EbpUndefined);
270 return;
271 }
272
273 TPrecision precision = EbpUndefined;
274 TIntermSequence::iterator childIter = mSequence.begin();
275 while (childIter != mSequence.end())
276 {
277 TIntermTyped *typed = (*childIter)->getAsTyped();
278 if (typed)
279 precision = GetHigherPrecision(typed->getPrecision(), precision);
280 ++childIter;
281 }
282 mType.setPrecision(precision);
283}
284
285void TIntermAggregate::setBuiltInFunctionPrecision()
286{
287 // All built-ins returning bool should be handled as ops, not functions.
288 ASSERT(getBasicType() != EbtBool);
289
290 TPrecision precision = EbpUndefined;
291 TIntermSequence::iterator childIter = mSequence.begin();
292 while (childIter != mSequence.end())
293 {
294 TIntermTyped *typed = (*childIter)->getAsTyped();
295 // ESSL spec section 8: texture functions get their precision from the sampler.
296 if (typed && IsSampler(typed->getBasicType()))
297 {
298 precision = typed->getPrecision();
299 break;
300 }
301 ++childIter;
302 }
303 // ESSL 3.0 spec section 8: textureSize always gets highp precision.
304 // All other functions that take a sampler are assumed to be texture functions.
305 if (mName.find("textureSize") == 0)
306 mType.setPrecision(EbpHigh);
307 else
308 mType.setPrecision(precision);
309}
310
Jamie Madillb1a85f42014-08-19 15:23:24 -0400311bool TIntermSelection::replaceChildNode(
312 TIntermNode *original, TIntermNode *replacement)
313{
314 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
315 REPLACE_IF_IS(mTrueBlock, TIntermNode, original, replacement);
316 REPLACE_IF_IS(mFalseBlock, TIntermNode, original, replacement);
317 return false;
318}
319
Olli Etuahoa3a36662015-02-17 13:46:51 +0200320bool TIntermSwitch::replaceChildNode(
321 TIntermNode *original, TIntermNode *replacement)
322{
323 REPLACE_IF_IS(mInit, TIntermTyped, original, replacement);
324 REPLACE_IF_IS(mStatementList, TIntermAggregate, original, replacement);
325 return false;
326}
327
328bool TIntermCase::replaceChildNode(
329 TIntermNode *original, TIntermNode *replacement)
330{
331 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
332 return false;
333}
334
Jamie Madillb1a85f42014-08-19 15:23:24 -0400335//
336// Say whether or not an operation node changes the value of a variable.
337//
338bool TIntermOperator::isAssignment() const
339{
340 switch (mOp)
341 {
342 case EOpPostIncrement:
343 case EOpPostDecrement:
344 case EOpPreIncrement:
345 case EOpPreDecrement:
346 case EOpAssign:
347 case EOpAddAssign:
348 case EOpSubAssign:
349 case EOpMulAssign:
350 case EOpVectorTimesMatrixAssign:
351 case EOpVectorTimesScalarAssign:
352 case EOpMatrixTimesScalarAssign:
353 case EOpMatrixTimesMatrixAssign:
354 case EOpDivAssign:
Olli Etuahoff805cc2015-02-13 10:59:34 +0200355 case EOpIModAssign:
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200356 case EOpBitShiftLeftAssign:
357 case EOpBitShiftRightAssign:
358 case EOpBitwiseAndAssign:
359 case EOpBitwiseXorAssign:
360 case EOpBitwiseOrAssign:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400361 return true;
362 default:
363 return false;
364 }
365}
366
367//
368// returns true if the operator is for one of the constructors
369//
370bool TIntermOperator::isConstructor() const
371{
372 switch (mOp)
373 {
374 case EOpConstructVec2:
375 case EOpConstructVec3:
376 case EOpConstructVec4:
377 case EOpConstructMat2:
378 case EOpConstructMat3:
379 case EOpConstructMat4:
380 case EOpConstructFloat:
381 case EOpConstructIVec2:
382 case EOpConstructIVec3:
383 case EOpConstructIVec4:
384 case EOpConstructInt:
385 case EOpConstructUVec2:
386 case EOpConstructUVec3:
387 case EOpConstructUVec4:
388 case EOpConstructUInt:
389 case EOpConstructBVec2:
390 case EOpConstructBVec3:
391 case EOpConstructBVec4:
392 case EOpConstructBool:
393 case EOpConstructStruct:
394 return true;
395 default:
396 return false;
397 }
398}
399
400//
401// Make sure the type of a unary operator is appropriate for its
402// combination of operation and operand type.
403//
Olli Etuahof6c694b2015-03-26 14:50:53 +0200404void TIntermUnary::promote(const TType *funcReturnType)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400405{
406 switch (mOp)
407 {
Olli Etuahodca3e792015-03-26 13:24:04 +0200408 case EOpFloatBitsToInt:
409 case EOpFloatBitsToUint:
Olli Etuahoe8d2c072015-01-08 16:33:54 +0200410 case EOpIntBitsToFloat:
411 case EOpUintBitsToFloat:
Olli Etuahodca3e792015-03-26 13:24:04 +0200412 case EOpPackSnorm2x16:
413 case EOpPackUnorm2x16:
414 case EOpPackHalf2x16:
Olli Etuaho7700ff62015-01-15 12:16:29 +0200415 case EOpUnpackSnorm2x16:
416 case EOpUnpackUnorm2x16:
Olli Etuahodca3e792015-03-26 13:24:04 +0200417 mType.setPrecision(EbpHigh);
Arun Patole6b19d762015-02-19 09:40:39 +0530418 break;
Olli Etuahodca3e792015-03-26 13:24:04 +0200419 case EOpUnpackHalf2x16:
420 mType.setPrecision(EbpMedium);
421 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400422 default:
Olli Etuahodca3e792015-03-26 13:24:04 +0200423 setType(mOperand->getType());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400424 }
425
Olli Etuahof6c694b2015-03-26 14:50:53 +0200426 if (funcReturnType != nullptr)
427 {
428 if (funcReturnType->getBasicType() == EbtBool)
429 {
430 // Bool types should not have precision.
431 setType(*funcReturnType);
432 }
433 else
434 {
435 // Precision of the node has been set based on the operand.
436 setTypePreservePrecision(*funcReturnType);
437 }
438 }
439
Jamie Madillb1a85f42014-08-19 15:23:24 -0400440 mType.setQualifier(EvqTemporary);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400441}
442
443//
444// Establishes the type of the resultant operation, as well as
445// makes the operator the correct one for the operands.
446//
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200447// For lots of operations it should already be established that the operand
448// combination is valid, but returns false if operator can't work on operands.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400449//
450bool TIntermBinary::promote(TInfoSink &infoSink)
451{
Olli Etuahoe79904c2015-03-18 16:56:42 +0200452 ASSERT(mLeft->isArray() == mRight->isArray());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400453
Jamie Madillb1a85f42014-08-19 15:23:24 -0400454 //
455 // Base assumption: just make the type the same as the left
456 // operand. Then only deviations from this need be coded.
457 //
458 setType(mLeft->getType());
459
460 // The result gets promoted to the highest precision.
461 TPrecision higherPrecision = GetHigherPrecision(
462 mLeft->getPrecision(), mRight->getPrecision());
463 getTypePointer()->setPrecision(higherPrecision);
464
465 // Binary operations results in temporary variables unless both
466 // operands are const.
467 if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst)
468 {
469 getTypePointer()->setQualifier(EvqTemporary);
470 }
471
472 const int nominalSize =
473 std::max(mLeft->getNominalSize(), mRight->getNominalSize());
474
475 //
476 // All scalars or structs. Code after this test assumes this case is removed!
477 //
478 if (nominalSize == 1)
479 {
480 switch (mOp)
481 {
482 //
483 // Promote to conditional
484 //
485 case EOpEqual:
486 case EOpNotEqual:
487 case EOpLessThan:
488 case EOpGreaterThan:
489 case EOpLessThanEqual:
490 case EOpGreaterThanEqual:
491 setType(TType(EbtBool, EbpUndefined));
492 break;
493
494 //
495 // And and Or operate on conditionals
496 //
497 case EOpLogicalAnd:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200498 case EOpLogicalXor:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400499 case EOpLogicalOr:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200500 ASSERT(mLeft->getBasicType() == EbtBool && mRight->getBasicType() == EbtBool);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400501 setType(TType(EbtBool, EbpUndefined));
502 break;
503
504 default:
505 break;
506 }
507 return true;
508 }
509
510 // If we reach here, at least one of the operands is vector or matrix.
511 // The other operand could be a scalar, vector, or matrix.
512 // Can these two operands be combined?
513 //
514 TBasicType basicType = mLeft->getBasicType();
515 switch (mOp)
516 {
517 case EOpMul:
518 if (!mLeft->isMatrix() && mRight->isMatrix())
519 {
520 if (mLeft->isVector())
521 {
522 mOp = EOpVectorTimesMatrix;
523 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700524 static_cast<unsigned char>(mRight->getCols()), 1));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400525 }
526 else
527 {
528 mOp = EOpMatrixTimesScalar;
529 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700530 static_cast<unsigned char>(mRight->getCols()), static_cast<unsigned char>(mRight->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400531 }
532 }
533 else if (mLeft->isMatrix() && !mRight->isMatrix())
534 {
535 if (mRight->isVector())
536 {
537 mOp = EOpMatrixTimesVector;
538 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700539 static_cast<unsigned char>(mLeft->getRows()), 1));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400540 }
541 else
542 {
543 mOp = EOpMatrixTimesScalar;
544 }
545 }
546 else if (mLeft->isMatrix() && mRight->isMatrix())
547 {
548 mOp = EOpMatrixTimesMatrix;
549 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700550 static_cast<unsigned char>(mRight->getCols()), static_cast<unsigned char>(mLeft->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400551 }
552 else if (!mLeft->isMatrix() && !mRight->isMatrix())
553 {
554 if (mLeft->isVector() && mRight->isVector())
555 {
556 // leave as component product
557 }
558 else if (mLeft->isVector() || mRight->isVector())
559 {
560 mOp = EOpVectorTimesScalar;
561 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700562 static_cast<unsigned char>(nominalSize), 1));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400563 }
564 }
565 else
566 {
567 infoSink.info.message(EPrefixInternalError, getLine(),
568 "Missing elses");
569 return false;
570 }
571
572 if (!ValidateMultiplication(mOp, mLeft->getType(), mRight->getType()))
573 {
574 return false;
575 }
576 break;
577
578 case EOpMulAssign:
579 if (!mLeft->isMatrix() && mRight->isMatrix())
580 {
581 if (mLeft->isVector())
582 {
583 mOp = EOpVectorTimesMatrixAssign;
584 }
585 else
586 {
587 return false;
588 }
589 }
590 else if (mLeft->isMatrix() && !mRight->isMatrix())
591 {
592 if (mRight->isVector())
593 {
594 return false;
595 }
596 else
597 {
598 mOp = EOpMatrixTimesScalarAssign;
599 }
600 }
601 else if (mLeft->isMatrix() && mRight->isMatrix())
602 {
603 mOp = EOpMatrixTimesMatrixAssign;
604 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700605 static_cast<unsigned char>(mRight->getCols()), static_cast<unsigned char>(mLeft->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400606 }
607 else if (!mLeft->isMatrix() && !mRight->isMatrix())
608 {
609 if (mLeft->isVector() && mRight->isVector())
610 {
611 // leave as component product
612 }
613 else if (mLeft->isVector() || mRight->isVector())
614 {
615 if (!mLeft->isVector())
616 return false;
617 mOp = EOpVectorTimesScalarAssign;
618 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700619 static_cast<unsigned char>(mLeft->getNominalSize()), 1));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400620 }
621 }
622 else
623 {
624 infoSink.info.message(EPrefixInternalError, getLine(),
625 "Missing elses");
626 return false;
627 }
628
629 if (!ValidateMultiplication(mOp, mLeft->getType(), mRight->getType()))
630 {
631 return false;
632 }
633 break;
634
635 case EOpAssign:
636 case EOpInitialize:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200637 // No more additional checks are needed.
638 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
639 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
640 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400641 case EOpAdd:
642 case EOpSub:
643 case EOpDiv:
Olli Etuahoff805cc2015-02-13 10:59:34 +0200644 case EOpIMod:
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200645 case EOpBitShiftLeft:
646 case EOpBitShiftRight:
647 case EOpBitwiseAnd:
648 case EOpBitwiseXor:
649 case EOpBitwiseOr:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400650 case EOpAddAssign:
651 case EOpSubAssign:
652 case EOpDivAssign:
Olli Etuahoff805cc2015-02-13 10:59:34 +0200653 case EOpIModAssign:
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200654 case EOpBitShiftLeftAssign:
655 case EOpBitShiftRightAssign:
656 case EOpBitwiseAndAssign:
657 case EOpBitwiseXorAssign:
658 case EOpBitwiseOrAssign:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400659 if ((mLeft->isMatrix() && mRight->isVector()) ||
660 (mLeft->isVector() && mRight->isMatrix()))
661 {
662 return false;
663 }
664
665 // Are the sizes compatible?
666 if (mLeft->getNominalSize() != mRight->getNominalSize() ||
667 mLeft->getSecondarySize() != mRight->getSecondarySize())
668 {
Olli Etuaho6c850472014-12-02 16:23:17 +0200669 // If the nominal sizes of operands do not match:
670 // One of them must be a scalar.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400671 if (!mLeft->isScalar() && !mRight->isScalar())
672 return false;
673
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200674 // In the case of compound assignment other than multiply-assign,
675 // the right side needs to be a scalar. Otherwise a vector/matrix
676 // would be assigned to a scalar. A scalar can't be shifted by a
677 // vector either.
Olli Etuaho6c850472014-12-02 16:23:17 +0200678 if (!mRight->isScalar() &&
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200679 (isAssignment() ||
680 mOp == EOpBitShiftLeft ||
681 mOp == EOpBitShiftRight))
Olli Etuaho6c850472014-12-02 16:23:17 +0200682 return false;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400683 }
684
685 {
686 const int secondarySize = std::max(
687 mLeft->getSecondarySize(), mRight->getSecondarySize());
688 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700689 static_cast<unsigned char>(nominalSize), static_cast<unsigned char>(secondarySize)));
Olli Etuahoe79904c2015-03-18 16:56:42 +0200690 if (mLeft->isArray())
691 {
692 ASSERT(mLeft->getArraySize() == mRight->getArraySize());
693 mType.setArraySize(mLeft->getArraySize());
694 }
Jamie Madillb1a85f42014-08-19 15:23:24 -0400695 }
696 break;
697
698 case EOpEqual:
699 case EOpNotEqual:
700 case EOpLessThan:
701 case EOpGreaterThan:
702 case EOpLessThanEqual:
703 case EOpGreaterThanEqual:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200704 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
705 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400706 setType(TType(EbtBool, EbpUndefined));
707 break;
708
709 default:
710 return false;
711 }
712 return true;
713}
714
715//
716// The fold functions see if an operation on a constant can be done in place,
717// without generating run-time code.
718//
719// Returns the node to keep using, which may or may not be the node passed in.
720//
721TIntermTyped *TIntermConstantUnion::fold(
Olli Etuaho2cb7b832015-04-23 20:27:44 +0300722 TOperator op, TIntermConstantUnion *rightNode, TInfoSink &infoSink)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400723{
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400724 TConstantUnion *unionArray = getUnionArrayPointer();
Jamie Madillb1a85f42014-08-19 15:23:24 -0400725
726 if (!unionArray)
Arun Patolefddc2112015-04-22 13:28:10 +0530727 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400728
729 size_t objectSize = getType().getObjectSize();
730
Olli Etuaho2cb7b832015-04-23 20:27:44 +0300731 if (rightNode)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400732 {
733 // binary operations
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400734 TConstantUnion *rightUnionArray = rightNode->getUnionArrayPointer();
Jamie Madillb1a85f42014-08-19 15:23:24 -0400735 TType returnType = getType();
736
737 if (!rightUnionArray)
Arun Patolefddc2112015-04-22 13:28:10 +0530738 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400739
Olli Etuaho2cb7b832015-04-23 20:27:44 +0300740 // for a case like float f = vec4(2, 3, 4, 5) + 1.2;
741 if (rightNode->getType().getObjectSize() == 1 && objectSize > 1)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400742 {
Arun Patole274f0702015-05-05 13:33:30 +0530743 rightUnionArray = Vectorize(*rightNode->getUnionArrayPointer(), objectSize);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400744 returnType = getType();
745 }
Olli Etuaho2cb7b832015-04-23 20:27:44 +0300746 else if (rightNode->getType().getObjectSize() > 1 && objectSize == 1)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400747 {
Olli Etuaho2cb7b832015-04-23 20:27:44 +0300748 // for a case like float f = 1.2 + vec4(2, 3, 4, 5);
Arun Patole274f0702015-05-05 13:33:30 +0530749 unionArray = Vectorize(*getUnionArrayPointer(), rightNode->getType().getObjectSize());
Olli Etuaho2cb7b832015-04-23 20:27:44 +0300750 returnType = rightNode->getType();
751 objectSize = rightNode->getType().getObjectSize();
Jamie Madillb1a85f42014-08-19 15:23:24 -0400752 }
753
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400754 TConstantUnion *tempConstArray = nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400755 TIntermConstantUnion *tempNode;
756
757 bool boolNodeFlag = false;
758 switch(op)
759 {
760 case EOpAdd:
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400761 tempConstArray = new TConstantUnion[objectSize];
Jamie Madillb1a85f42014-08-19 15:23:24 -0400762 for (size_t i = 0; i < objectSize; i++)
763 tempConstArray[i] = unionArray[i] + rightUnionArray[i];
764 break;
765 case EOpSub:
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400766 tempConstArray = new TConstantUnion[objectSize];
Jamie Madillb1a85f42014-08-19 15:23:24 -0400767 for (size_t i = 0; i < objectSize; i++)
768 tempConstArray[i] = unionArray[i] - rightUnionArray[i];
769 break;
770
771 case EOpMul:
772 case EOpVectorTimesScalar:
773 case EOpMatrixTimesScalar:
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400774 tempConstArray = new TConstantUnion[objectSize];
Jamie Madillb1a85f42014-08-19 15:23:24 -0400775 for (size_t i = 0; i < objectSize; i++)
776 tempConstArray[i] = unionArray[i] * rightUnionArray[i];
777 break;
778
779 case EOpMatrixTimesMatrix:
780 {
781 if (getType().getBasicType() != EbtFloat ||
Olli Etuaho2cb7b832015-04-23 20:27:44 +0300782 rightNode->getBasicType() != EbtFloat)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400783 {
784 infoSink.info.message(
785 EPrefixInternalError, getLine(),
786 "Constant Folding cannot be done for matrix multiply");
Arun Patolefddc2112015-04-22 13:28:10 +0530787 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400788 }
789
790 const int leftCols = getCols();
791 const int leftRows = getRows();
Olli Etuaho2cb7b832015-04-23 20:27:44 +0300792 const int rightCols = rightNode->getType().getCols();
793 const int rightRows = rightNode->getType().getRows();
Jamie Madillb1a85f42014-08-19 15:23:24 -0400794 const int resultCols = rightCols;
795 const int resultRows = leftRows;
796
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400797 tempConstArray = new TConstantUnion[resultCols * resultRows];
Jamie Madillb1a85f42014-08-19 15:23:24 -0400798 for (int row = 0; row < resultRows; row++)
799 {
800 for (int column = 0; column < resultCols; column++)
801 {
802 tempConstArray[resultRows * column + row].setFConst(0.0f);
803 for (int i = 0; i < leftCols; i++)
804 {
805 tempConstArray[resultRows * column + row].setFConst(
806 tempConstArray[resultRows * column + row].getFConst() +
807 unionArray[i * leftRows + row].getFConst() *
808 rightUnionArray[column * rightRows + i].getFConst());
809 }
810 }
811 }
812
813 // update return type for matrix product
Minmin Gong794e0002015-04-07 18:31:54 -0700814 returnType.setPrimarySize(static_cast<unsigned char>(resultCols));
815 returnType.setSecondarySize(static_cast<unsigned char>(resultRows));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400816 }
817 break;
818
819 case EOpDiv:
Olli Etuahoff805cc2015-02-13 10:59:34 +0200820 case EOpIMod:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400821 {
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400822 tempConstArray = new TConstantUnion[objectSize];
Jamie Madillb1a85f42014-08-19 15:23:24 -0400823 for (size_t i = 0; i < objectSize; i++)
824 {
825 switch (getType().getBasicType())
826 {
827 case EbtFloat:
828 if (rightUnionArray[i] == 0.0f)
829 {
830 infoSink.info.message(
831 EPrefixWarning, getLine(),
832 "Divide by zero error during constant folding");
833 tempConstArray[i].setFConst(
834 unionArray[i].getFConst() < 0 ? -FLT_MAX : FLT_MAX);
835 }
836 else
837 {
Olli Etuaho3eab00a2015-02-12 16:02:39 +0200838 ASSERT(op == EOpDiv);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400839 tempConstArray[i].setFConst(
840 unionArray[i].getFConst() /
841 rightUnionArray[i].getFConst());
842 }
843 break;
844
845 case EbtInt:
846 if (rightUnionArray[i] == 0)
847 {
848 infoSink.info.message(
849 EPrefixWarning, getLine(),
850 "Divide by zero error during constant folding");
851 tempConstArray[i].setIConst(INT_MAX);
852 }
853 else
854 {
Olli Etuaho3eab00a2015-02-12 16:02:39 +0200855 if (op == EOpDiv)
856 {
857 tempConstArray[i].setIConst(
858 unionArray[i].getIConst() /
859 rightUnionArray[i].getIConst());
860 }
861 else
862 {
863 ASSERT(op == EOpIMod);
864 tempConstArray[i].setIConst(
865 unionArray[i].getIConst() %
866 rightUnionArray[i].getIConst());
867 }
Jamie Madillb1a85f42014-08-19 15:23:24 -0400868 }
869 break;
870
871 case EbtUInt:
872 if (rightUnionArray[i] == 0)
873 {
874 infoSink.info.message(
875 EPrefixWarning, getLine(),
876 "Divide by zero error during constant folding");
877 tempConstArray[i].setUConst(UINT_MAX);
878 }
879 else
880 {
Olli Etuaho3eab00a2015-02-12 16:02:39 +0200881 if (op == EOpDiv)
882 {
883 tempConstArray[i].setUConst(
884 unionArray[i].getUConst() /
885 rightUnionArray[i].getUConst());
886 }
887 else
888 {
889 ASSERT(op == EOpIMod);
890 tempConstArray[i].setUConst(
891 unionArray[i].getUConst() %
892 rightUnionArray[i].getUConst());
893 }
Jamie Madillb1a85f42014-08-19 15:23:24 -0400894 }
895 break;
896
897 default:
898 infoSink.info.message(
899 EPrefixInternalError, getLine(),
900 "Constant folding cannot be done for \"/\"");
Arun Patolefddc2112015-04-22 13:28:10 +0530901 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400902 }
903 }
904 }
905 break;
906
907 case EOpMatrixTimesVector:
908 {
Olli Etuaho2cb7b832015-04-23 20:27:44 +0300909 if (rightNode->getBasicType() != EbtFloat)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400910 {
911 infoSink.info.message(
912 EPrefixInternalError, getLine(),
913 "Constant Folding cannot be done for matrix times vector");
Arun Patolefddc2112015-04-22 13:28:10 +0530914 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400915 }
916
917 const int matrixCols = getCols();
918 const int matrixRows = getRows();
919
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400920 tempConstArray = new TConstantUnion[matrixRows];
Jamie Madillb1a85f42014-08-19 15:23:24 -0400921
922 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
923 {
924 tempConstArray[matrixRow].setFConst(0.0f);
925 for (int col = 0; col < matrixCols; col++)
926 {
927 tempConstArray[matrixRow].setFConst(
928 tempConstArray[matrixRow].getFConst() +
929 unionArray[col * matrixRows + matrixRow].getFConst() *
930 rightUnionArray[col].getFConst());
931 }
932 }
933
Olli Etuaho2cb7b832015-04-23 20:27:44 +0300934 returnType = rightNode->getType();
Minmin Gong794e0002015-04-07 18:31:54 -0700935 returnType.setPrimarySize(static_cast<unsigned char>(matrixRows));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400936
937 tempNode = new TIntermConstantUnion(tempConstArray, returnType);
938 tempNode->setLine(getLine());
939
940 return tempNode;
941 }
942
943 case EOpVectorTimesMatrix:
944 {
945 if (getType().getBasicType() != EbtFloat)
946 {
947 infoSink.info.message(
948 EPrefixInternalError, getLine(),
949 "Constant Folding cannot be done for vector times matrix");
Arun Patolefddc2112015-04-22 13:28:10 +0530950 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400951 }
952
Olli Etuaho2cb7b832015-04-23 20:27:44 +0300953 const int matrixCols = rightNode->getType().getCols();
954 const int matrixRows = rightNode->getType().getRows();
Jamie Madillb1a85f42014-08-19 15:23:24 -0400955
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400956 tempConstArray = new TConstantUnion[matrixCols];
Jamie Madillb1a85f42014-08-19 15:23:24 -0400957
958 for (int matrixCol = 0; matrixCol < matrixCols; matrixCol++)
959 {
960 tempConstArray[matrixCol].setFConst(0.0f);
961 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
962 {
963 tempConstArray[matrixCol].setFConst(
964 tempConstArray[matrixCol].getFConst() +
965 unionArray[matrixRow].getFConst() *
966 rightUnionArray[matrixCol * matrixRows + matrixRow].getFConst());
967 }
968 }
969
Minmin Gong794e0002015-04-07 18:31:54 -0700970 returnType.setPrimarySize(static_cast<unsigned char>(matrixCols));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400971 }
972 break;
973
974 case EOpLogicalAnd:
975 // this code is written for possible future use,
976 // will not get executed currently
977 {
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400978 tempConstArray = new TConstantUnion[objectSize];
Jamie Madillb1a85f42014-08-19 15:23:24 -0400979 for (size_t i = 0; i < objectSize; i++)
980 {
981 tempConstArray[i] = unionArray[i] && rightUnionArray[i];
982 }
983 }
984 break;
985
986 case EOpLogicalOr:
987 // this code is written for possible future use,
988 // will not get executed currently
989 {
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400990 tempConstArray = new TConstantUnion[objectSize];
Jamie Madillb1a85f42014-08-19 15:23:24 -0400991 for (size_t i = 0; i < objectSize; i++)
992 {
993 tempConstArray[i] = unionArray[i] || rightUnionArray[i];
994 }
995 }
996 break;
997
998 case EOpLogicalXor:
999 {
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001000 tempConstArray = new TConstantUnion[objectSize];
Jamie Madillb1a85f42014-08-19 15:23:24 -04001001 for (size_t i = 0; i < objectSize; i++)
1002 {
1003 switch (getType().getBasicType())
1004 {
1005 case EbtBool:
1006 tempConstArray[i].setBConst(
1007 unionArray[i] == rightUnionArray[i] ? false : true);
1008 break;
1009 default:
1010 UNREACHABLE();
1011 break;
1012 }
1013 }
1014 }
1015 break;
1016
Olli Etuaho31b5fc62015-01-16 12:13:36 +02001017 case EOpBitwiseAnd:
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001018 tempConstArray = new TConstantUnion[objectSize];
Olli Etuaho31b5fc62015-01-16 12:13:36 +02001019 for (size_t i = 0; i < objectSize; i++)
1020 tempConstArray[i] = unionArray[i] & rightUnionArray[i];
1021 break;
1022 case EOpBitwiseXor:
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001023 tempConstArray = new TConstantUnion[objectSize];
Olli Etuaho31b5fc62015-01-16 12:13:36 +02001024 for (size_t i = 0; i < objectSize; i++)
1025 tempConstArray[i] = unionArray[i] ^ rightUnionArray[i];
1026 break;
1027 case EOpBitwiseOr:
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001028 tempConstArray = new TConstantUnion[objectSize];
Olli Etuaho31b5fc62015-01-16 12:13:36 +02001029 for (size_t i = 0; i < objectSize; i++)
1030 tempConstArray[i] = unionArray[i] | rightUnionArray[i];
1031 break;
1032 case EOpBitShiftLeft:
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001033 tempConstArray = new TConstantUnion[objectSize];
Olli Etuaho31b5fc62015-01-16 12:13:36 +02001034 for (size_t i = 0; i < objectSize; i++)
1035 tempConstArray[i] = unionArray[i] << rightUnionArray[i];
1036 break;
1037 case EOpBitShiftRight:
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001038 tempConstArray = new TConstantUnion[objectSize];
Olli Etuaho31b5fc62015-01-16 12:13:36 +02001039 for (size_t i = 0; i < objectSize; i++)
1040 tempConstArray[i] = unionArray[i] >> rightUnionArray[i];
1041 break;
1042
Jamie Madillb1a85f42014-08-19 15:23:24 -04001043 case EOpLessThan:
1044 ASSERT(objectSize == 1);
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001045 tempConstArray = new TConstantUnion[1];
Jamie Madillb1a85f42014-08-19 15:23:24 -04001046 tempConstArray->setBConst(*unionArray < *rightUnionArray);
1047 returnType = TType(EbtBool, EbpUndefined, EvqConst);
1048 break;
1049
1050 case EOpGreaterThan:
1051 ASSERT(objectSize == 1);
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001052 tempConstArray = new TConstantUnion[1];
Jamie Madillb1a85f42014-08-19 15:23:24 -04001053 tempConstArray->setBConst(*unionArray > *rightUnionArray);
1054 returnType = TType(EbtBool, EbpUndefined, EvqConst);
1055 break;
1056
1057 case EOpLessThanEqual:
1058 {
1059 ASSERT(objectSize == 1);
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001060 TConstantUnion constant;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001061 constant.setBConst(*unionArray > *rightUnionArray);
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001062 tempConstArray = new TConstantUnion[1];
Jamie Madillb1a85f42014-08-19 15:23:24 -04001063 tempConstArray->setBConst(!constant.getBConst());
1064 returnType = TType(EbtBool, EbpUndefined, EvqConst);
1065 break;
1066 }
1067
1068 case EOpGreaterThanEqual:
1069 {
1070 ASSERT(objectSize == 1);
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001071 TConstantUnion constant;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001072 constant.setBConst(*unionArray < *rightUnionArray);
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001073 tempConstArray = new TConstantUnion[1];
Jamie Madillb1a85f42014-08-19 15:23:24 -04001074 tempConstArray->setBConst(!constant.getBConst());
1075 returnType = TType(EbtBool, EbpUndefined, EvqConst);
1076 break;
1077 }
1078
1079 case EOpEqual:
1080 if (getType().getBasicType() == EbtStruct)
1081 {
Olli Etuaho2cb7b832015-04-23 20:27:44 +03001082 if (!CompareStructure(rightNode->getType(),
1083 rightNode->getUnionArrayPointer(),
Jamie Madillb1a85f42014-08-19 15:23:24 -04001084 unionArray))
1085 {
1086 boolNodeFlag = true;
1087 }
1088 }
1089 else
1090 {
1091 for (size_t i = 0; i < objectSize; i++)
1092 {
1093 if (unionArray[i] != rightUnionArray[i])
1094 {
1095 boolNodeFlag = true;
1096 break; // break out of for loop
1097 }
1098 }
1099 }
1100
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001101 tempConstArray = new TConstantUnion[1];
Jamie Madillb1a85f42014-08-19 15:23:24 -04001102 if (!boolNodeFlag)
1103 {
1104 tempConstArray->setBConst(true);
1105 }
1106 else
1107 {
1108 tempConstArray->setBConst(false);
1109 }
1110
1111 tempNode = new TIntermConstantUnion(
1112 tempConstArray, TType(EbtBool, EbpUndefined, EvqConst));
1113 tempNode->setLine(getLine());
1114
1115 return tempNode;
1116
1117 case EOpNotEqual:
1118 if (getType().getBasicType() == EbtStruct)
1119 {
Olli Etuaho2cb7b832015-04-23 20:27:44 +03001120 if (CompareStructure(rightNode->getType(),
1121 rightNode->getUnionArrayPointer(),
Jamie Madillb1a85f42014-08-19 15:23:24 -04001122 unionArray))
1123 {
1124 boolNodeFlag = true;
1125 }
1126 }
1127 else
1128 {
1129 for (size_t i = 0; i < objectSize; i++)
1130 {
1131 if (unionArray[i] == rightUnionArray[i])
1132 {
1133 boolNodeFlag = true;
1134 break; // break out of for loop
1135 }
1136 }
1137 }
1138
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001139 tempConstArray = new TConstantUnion[1];
Jamie Madillb1a85f42014-08-19 15:23:24 -04001140 if (!boolNodeFlag)
1141 {
1142 tempConstArray->setBConst(true);
1143 }
1144 else
1145 {
1146 tempConstArray->setBConst(false);
1147 }
1148
1149 tempNode = new TIntermConstantUnion(
1150 tempConstArray, TType(EbtBool, EbpUndefined, EvqConst));
1151 tempNode->setLine(getLine());
1152
1153 return tempNode;
1154
1155 default:
1156 infoSink.info.message(
1157 EPrefixInternalError, getLine(),
1158 "Invalid operator for constant folding");
Arun Patolefddc2112015-04-22 13:28:10 +05301159 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001160 }
1161 tempNode = new TIntermConstantUnion(tempConstArray, returnType);
1162 tempNode->setLine(getLine());
1163
1164 return tempNode;
1165 }
1166 else
1167 {
1168 //
1169 // Do unary operations
1170 //
1171 TIntermConstantUnion *newNode = 0;
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001172 TConstantUnion* tempConstArray = new TConstantUnion[objectSize];
Jamie Madillb1a85f42014-08-19 15:23:24 -04001173 for (size_t i = 0; i < objectSize; i++)
1174 {
1175 switch(op)
1176 {
1177 case EOpNegative:
1178 switch (getType().getBasicType())
1179 {
1180 case EbtFloat:
1181 tempConstArray[i].setFConst(-unionArray[i].getFConst());
1182 break;
1183 case EbtInt:
1184 tempConstArray[i].setIConst(-unionArray[i].getIConst());
1185 break;
1186 case EbtUInt:
1187 tempConstArray[i].setUConst(static_cast<unsigned int>(
1188 -static_cast<int>(unionArray[i].getUConst())));
1189 break;
1190 default:
1191 infoSink.info.message(
1192 EPrefixInternalError, getLine(),
1193 "Unary operation not folded into constant");
Arun Patolefddc2112015-04-22 13:28:10 +05301194 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001195 }
1196 break;
1197
Zhenyao Mode1e00e2014-10-09 16:55:32 -07001198 case EOpPositive:
1199 switch (getType().getBasicType())
1200 {
1201 case EbtFloat:
1202 tempConstArray[i].setFConst(unionArray[i].getFConst());
1203 break;
1204 case EbtInt:
1205 tempConstArray[i].setIConst(unionArray[i].getIConst());
1206 break;
1207 case EbtUInt:
1208 tempConstArray[i].setUConst(static_cast<unsigned int>(
1209 static_cast<int>(unionArray[i].getUConst())));
1210 break;
1211 default:
1212 infoSink.info.message(
1213 EPrefixInternalError, getLine(),
1214 "Unary operation not folded into constant");
Arun Patolefddc2112015-04-22 13:28:10 +05301215 return nullptr;
Zhenyao Mode1e00e2014-10-09 16:55:32 -07001216 }
1217 break;
1218
Jamie Madillb1a85f42014-08-19 15:23:24 -04001219 case EOpLogicalNot:
1220 // this code is written for possible future use,
1221 // will not get executed currently
1222 switch (getType().getBasicType())
1223 {
1224 case EbtBool:
1225 tempConstArray[i].setBConst(!unionArray[i].getBConst());
1226 break;
1227 default:
1228 infoSink.info.message(
1229 EPrefixInternalError, getLine(),
1230 "Unary operation not folded into constant");
Arun Patolefddc2112015-04-22 13:28:10 +05301231 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001232 }
1233 break;
1234
Olli Etuaho31b5fc62015-01-16 12:13:36 +02001235 case EOpBitwiseNot:
1236 switch (getType().getBasicType())
1237 {
1238 case EbtInt:
1239 tempConstArray[i].setIConst(~unionArray[i].getIConst());
1240 break;
1241 case EbtUInt:
1242 tempConstArray[i].setUConst(~unionArray[i].getUConst());
1243 break;
1244 default:
1245 infoSink.info.message(
1246 EPrefixInternalError, getLine(),
1247 "Unary operation not folded into constant");
Arun Patolefddc2112015-04-22 13:28:10 +05301248 return nullptr;
Olli Etuaho31b5fc62015-01-16 12:13:36 +02001249 }
1250 break;
1251
Arun Patole9dea48f2015-04-02 11:45:09 +05301252 case EOpRadians:
1253 if (getType().getBasicType() == EbtFloat)
1254 {
1255 tempConstArray[i].setFConst(kDegreesToRadiansMultiplier * unionArray[i].getFConst());
1256 break;
1257 }
1258 infoSink.info.message(
1259 EPrefixInternalError, getLine(),
1260 "Unary operation not folded into constant");
1261 return nullptr;
1262
1263 case EOpDegrees:
1264 if (getType().getBasicType() == EbtFloat)
1265 {
1266 tempConstArray[i].setFConst(kRadiansToDegreesMultiplier * unionArray[i].getFConst());
1267 break;
1268 }
1269 infoSink.info.message(
1270 EPrefixInternalError, getLine(),
1271 "Unary operation not folded into constant");
1272 return nullptr;
1273
1274 case EOpSin:
1275 if (!foldFloatTypeUnary(unionArray[i], &sinf, infoSink, &tempConstArray[i]))
1276 return nullptr;
1277 break;
1278
1279 case EOpCos:
1280 if (!foldFloatTypeUnary(unionArray[i], &cosf, infoSink, &tempConstArray[i]))
1281 return nullptr;
1282 break;
1283
1284 case EOpTan:
1285 if (!foldFloatTypeUnary(unionArray[i], &tanf, infoSink, &tempConstArray[i]))
1286 return nullptr;
1287 break;
1288
1289 case EOpAsin:
1290 // For asin(x), results are undefined if |x| > 1, we are choosing to set result to 0.
1291 if (getType().getBasicType() == EbtFloat && fabsf(unionArray[i].getFConst()) > 1.0f)
1292 tempConstArray[i].setFConst(0.0f);
1293 else if (!foldFloatTypeUnary(unionArray[i], &asinf, infoSink, &tempConstArray[i]))
1294 return nullptr;
1295 break;
1296
1297 case EOpAcos:
1298 // For acos(x), results are undefined if |x| > 1, we are choosing to set result to 0.
1299 if (getType().getBasicType() == EbtFloat && fabsf(unionArray[i].getFConst()) > 1.0f)
1300 tempConstArray[i].setFConst(0.0f);
1301 else if (!foldFloatTypeUnary(unionArray[i], &acosf, infoSink, &tempConstArray[i]))
1302 return nullptr;
1303 break;
1304
1305 case EOpAtan:
1306 if (!foldFloatTypeUnary(unionArray[i], &atanf, infoSink, &tempConstArray[i]))
1307 return nullptr;
1308 break;
1309
1310 case EOpSinh:
1311 if (!foldFloatTypeUnary(unionArray[i], &sinhf, infoSink, &tempConstArray[i]))
1312 return nullptr;
1313 break;
1314
1315 case EOpCosh:
1316 if (!foldFloatTypeUnary(unionArray[i], &coshf, infoSink, &tempConstArray[i]))
1317 return nullptr;
1318 break;
1319
1320 case EOpTanh:
1321 if (!foldFloatTypeUnary(unionArray[i], &tanhf, infoSink, &tempConstArray[i]))
1322 return nullptr;
1323 break;
1324
1325 case EOpAsinh:
1326 if (!foldFloatTypeUnary(unionArray[i], &asinhf, infoSink, &tempConstArray[i]))
1327 return nullptr;
1328 break;
1329
1330 case EOpAcosh:
1331 // For acosh(x), results are undefined if x < 1, we are choosing to set result to 0.
1332 if (getType().getBasicType() == EbtFloat && unionArray[i].getFConst() < 1.0f)
1333 tempConstArray[i].setFConst(0.0f);
1334 else if (!foldFloatTypeUnary(unionArray[i], &acoshf, infoSink, &tempConstArray[i]))
1335 return nullptr;
1336 break;
1337
1338 case EOpAtanh:
1339 // For atanh(x), results are undefined if |x| >= 1, we are choosing to set result to 0.
1340 if (getType().getBasicType() == EbtFloat && fabsf(unionArray[i].getFConst()) >= 1.0f)
1341 tempConstArray[i].setFConst(0.0f);
1342 else if (!foldFloatTypeUnary(unionArray[i], &atanhf, infoSink, &tempConstArray[i]))
1343 return nullptr;
1344 break;
1345
Arun Patole97dc22e2015-04-06 17:35:38 +05301346 case EOpAbs:
1347 switch (getType().getBasicType())
1348 {
1349 case EbtFloat:
1350 tempConstArray[i].setFConst(fabsf(unionArray[i].getFConst()));
1351 break;
1352 case EbtInt:
1353 tempConstArray[i].setIConst(abs(unionArray[i].getIConst()));
1354 break;
1355 default:
1356 infoSink.info.message(
1357 EPrefixInternalError, getLine(),
1358 "Unary operation not folded into constant");
1359 return nullptr;
1360 }
1361 break;
1362
1363 case EOpSign:
1364 switch (getType().getBasicType())
1365 {
1366 case EbtFloat:
1367 {
1368 float fConst = unionArray[i].getFConst();
1369 float fResult = 0.0f;
1370 if (fConst > 0.0f)
1371 fResult = 1.0f;
1372 else if (fConst < 0.0f)
1373 fResult = -1.0f;
1374 tempConstArray[i].setFConst(fResult);
1375 }
1376 break;
1377 case EbtInt:
1378 {
1379 int iConst = unionArray[i].getIConst();
1380 int iResult = 0;
1381 if (iConst > 0)
1382 iResult = 1;
1383 else if (iConst < 0)
1384 iResult = -1;
1385 tempConstArray[i].setIConst(iResult);
1386 }
1387 break;
1388 default:
1389 infoSink.info.message(
1390 EPrefixInternalError, getLine(),
1391 "Unary operation not folded into constant");
1392 return nullptr;
1393 }
1394 break;
1395
1396 case EOpFloor:
1397 if (!foldFloatTypeUnary(unionArray[i], &floorf, infoSink, &tempConstArray[i]))
1398 return nullptr;
1399 break;
1400
1401 case EOpTrunc:
1402 if (!foldFloatTypeUnary(unionArray[i], &truncf, infoSink, &tempConstArray[i]))
1403 return nullptr;
1404 break;
1405
1406 case EOpRound:
1407 if (!foldFloatTypeUnary(unionArray[i], &roundf, infoSink, &tempConstArray[i]))
1408 return nullptr;
1409 break;
1410
1411 case EOpRoundEven:
1412 if (getType().getBasicType() == EbtFloat)
1413 {
1414 float x = unionArray[i].getFConst();
1415 float result;
1416 float fractPart = modff(x, &result);
1417 if (fabsf(fractPart) == 0.5f)
1418 result = 2.0f * roundf(x / 2.0f);
1419 else
1420 result = roundf(x);
1421 tempConstArray[i].setFConst(result);
1422 break;
1423 }
1424 infoSink.info.message(
1425 EPrefixInternalError, getLine(),
1426 "Unary operation not folded into constant");
1427 return nullptr;
1428
1429 case EOpCeil:
1430 if (!foldFloatTypeUnary(unionArray[i], &ceilf, infoSink, &tempConstArray[i]))
1431 return nullptr;
1432 break;
1433
1434 case EOpFract:
1435 if (getType().getBasicType() == EbtFloat)
1436 {
1437 float x = unionArray[i].getFConst();
1438 tempConstArray[i].setFConst(x - floorf(x));
1439 break;
1440 }
1441 infoSink.info.message(
1442 EPrefixInternalError, getLine(),
1443 "Unary operation not folded into constant");
1444 return nullptr;
1445
Arun Patole28eb65e2015-04-06 17:29:48 +05301446 case EOpExp:
1447 if (!foldFloatTypeUnary(unionArray[i], &expf, infoSink, &tempConstArray[i]))
1448 return nullptr;
1449 break;
1450
1451 case EOpLog:
1452 // For log(x), results are undefined if x <= 0, we are choosing to set result to 0.
1453 if (getType().getBasicType() == EbtFloat && unionArray[i].getFConst() <= 0.0f)
1454 tempConstArray[i].setFConst(0.0f);
1455 else if (!foldFloatTypeUnary(unionArray[i], &logf, infoSink, &tempConstArray[i]))
1456 return nullptr;
1457 break;
1458
1459 case EOpExp2:
1460 if (!foldFloatTypeUnary(unionArray[i], &exp2f, infoSink, &tempConstArray[i]))
1461 return nullptr;
1462 break;
1463
1464 case EOpLog2:
1465 // For log2(x), results are undefined if x <= 0, we are choosing to set result to 0.
1466 // And log2f is not available on some plarforms like old android, so just using log(x)/log(2) here.
1467 if (getType().getBasicType() == EbtFloat && unionArray[i].getFConst() <= 0.0f)
1468 tempConstArray[i].setFConst(0.0f);
1469 else if (!foldFloatTypeUnary(unionArray[i], &logf, infoSink, &tempConstArray[i]))
1470 return nullptr;
1471 else
1472 tempConstArray[i].setFConst(tempConstArray[i].getFConst() / logf(2.0f));
1473 break;
1474
1475 case EOpSqrt:
1476 // For sqrt(x), results are undefined if x < 0, we are choosing to set result to 0.
1477 if (getType().getBasicType() == EbtFloat && unionArray[i].getFConst() < 0.0f)
1478 tempConstArray[i].setFConst(0.0f);
1479 else if (!foldFloatTypeUnary(unionArray[i], &sqrtf, infoSink, &tempConstArray[i]))
1480 return nullptr;
1481 break;
1482
1483 case EOpInverseSqrt:
1484 // There is no stdlib built-in function equavalent for GLES built-in inversesqrt(),
1485 // so getting the square root first using builtin function sqrt() and then taking its inverse.
1486 // Also, for inversesqrt(x), results are undefined if x <= 0, we are choosing to set result to 0.
1487 if (getType().getBasicType() == EbtFloat && unionArray[i].getFConst() <= 0.0f)
1488 tempConstArray[i].setFConst(0.0f);
1489 else if (!foldFloatTypeUnary(unionArray[i], &sqrtf, infoSink, &tempConstArray[i]))
1490 return nullptr;
1491 else
1492 tempConstArray[i].setFConst(1.0f / tempConstArray[i].getFConst());
1493 break;
1494
Jamie Madillb1a85f42014-08-19 15:23:24 -04001495 default:
Arun Patolefddc2112015-04-22 13:28:10 +05301496 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001497 }
1498 }
1499 newNode = new TIntermConstantUnion(tempConstArray, getType());
1500 newNode->setLine(getLine());
1501 return newNode;
1502 }
1503}
1504
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001505bool TIntermConstantUnion::foldFloatTypeUnary(const TConstantUnion &parameter, FloatTypeUnaryFunc builtinFunc,
1506 TInfoSink &infoSink, TConstantUnion *result) const
Arun Patole9dea48f2015-04-02 11:45:09 +05301507{
1508 ASSERT(builtinFunc);
1509
1510 if (getType().getBasicType() == EbtFloat)
1511 {
1512 result->setFConst(builtinFunc(parameter.getFConst()));
1513 return true;
1514 }
1515
1516 infoSink.info.message(
1517 EPrefixInternalError, getLine(),
1518 "Unary operation not folded into constant");
1519 return false;
1520}
1521
Jamie Madillb1a85f42014-08-19 15:23:24 -04001522// static
Arun Patolebf790422015-05-18 17:53:04 +05301523TIntermTyped *TIntermConstantUnion::FoldAggregateBuiltIn(TOperator op, TIntermAggregate *aggregate, TInfoSink &infoSink)
Arun Patole274f0702015-05-05 13:33:30 +05301524{
1525 TIntermSequence *sequence = aggregate->getSequence();
1526 unsigned int paramsCount = sequence->size();
1527 std::vector<TConstantUnion *> unionArrays(paramsCount);
1528 std::vector<size_t> objectSizes(paramsCount);
1529 TType *maxSizeType = nullptr;
1530 TBasicType basicType = EbtVoid;
1531 TSourceLoc loc;
1532 for (unsigned int i = 0; i < paramsCount; i++)
1533 {
1534 TIntermConstantUnion *paramConstant = (*sequence)[i]->getAsConstantUnion();
1535 // Make sure that all params are constant before actual constant folding.
1536 if (!paramConstant)
1537 return nullptr;
1538
1539 if (i == 0)
1540 {
1541 basicType = paramConstant->getType().getBasicType();
1542 loc = paramConstant->getLine();
1543 }
1544 unionArrays[i] = paramConstant->getUnionArrayPointer();
1545 objectSizes[i] = paramConstant->getType().getObjectSize();
1546 if (maxSizeType == nullptr || (objectSizes[i] >= maxSizeType->getObjectSize()))
1547 maxSizeType = paramConstant->getTypePointer();
1548 }
1549
1550 size_t maxObjectSize = maxSizeType->getObjectSize();
1551 for (unsigned int i = 0; i < paramsCount; i++)
1552 if (objectSizes[i] != maxObjectSize)
1553 unionArrays[i] = Vectorize(*unionArrays[i], maxObjectSize);
1554
1555 TConstantUnion *tempConstArray = nullptr;
1556 TIntermConstantUnion *tempNode = nullptr;
1557 TType returnType = *maxSizeType;
1558 if (paramsCount == 2)
1559 {
1560 //
1561 // Binary built-in
1562 //
1563 switch (op)
1564 {
Arun Patolebf790422015-05-18 17:53:04 +05301565 case EOpAtan:
1566 {
1567 if (basicType == EbtFloat)
1568 {
1569 tempConstArray = new TConstantUnion[maxObjectSize];
1570 for (size_t i = 0; i < maxObjectSize; i++)
1571 {
1572 float y = unionArrays[0][i].getFConst();
1573 float x = unionArrays[1][i].getFConst();
1574 // Results are undefined if x and y are both 0.
1575 if (x == 0.0f && y == 0.0f)
1576 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &tempConstArray[i]);
1577 else
1578 tempConstArray[i].setFConst(atan2f(y, x));
1579 }
1580 }
1581 else
1582 UNREACHABLE();
1583 }
1584 break;
1585
1586 case EOpPow:
1587 {
1588 if (basicType == EbtFloat)
1589 {
1590 tempConstArray = new TConstantUnion[maxObjectSize];
1591 for (size_t i = 0; i < maxObjectSize; i++)
1592 {
1593 float x = unionArrays[0][i].getFConst();
1594 float y = unionArrays[1][i].getFConst();
1595 // Results are undefined if x < 0.
1596 // Results are undefined if x = 0 and y <= 0.
1597 if (x < 0.0f)
1598 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &tempConstArray[i]);
1599 else if (x == 0.0f && y <= 0.0f)
1600 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &tempConstArray[i]);
1601 else
1602 tempConstArray[i].setFConst(powf(x, y));
1603 }
1604 }
1605 else
1606 UNREACHABLE();
1607 }
1608 break;
1609
1610 case EOpMod:
1611 {
1612 if (basicType == EbtFloat)
1613 {
1614 tempConstArray = new TConstantUnion[maxObjectSize];
1615 for (size_t i = 0; i < maxObjectSize; i++)
1616 {
1617 float x = unionArrays[0][i].getFConst();
1618 float y = unionArrays[1][i].getFConst();
1619 tempConstArray[i].setFConst(x - y * floorf(x / y));
1620 }
1621 }
1622 else
1623 UNREACHABLE();
1624 }
1625 break;
1626
Arun Patole274f0702015-05-05 13:33:30 +05301627 case EOpMin:
1628 {
1629 tempConstArray = new TConstantUnion[maxObjectSize];
1630 for (size_t i = 0; i < maxObjectSize; i++)
1631 {
1632 switch (basicType)
1633 {
1634 case EbtFloat:
1635 tempConstArray[i].setFConst(std::min(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
1636 break;
1637 case EbtInt:
1638 tempConstArray[i].setIConst(std::min(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
1639 break;
1640 case EbtUInt:
1641 tempConstArray[i].setUConst(std::min(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
1642 break;
1643 default:
1644 UNREACHABLE();
1645 break;
1646 }
1647 }
1648 }
1649 break;
1650
1651 case EOpMax:
1652 {
1653 tempConstArray = new TConstantUnion[maxObjectSize];
1654 for (size_t i = 0; i < maxObjectSize; i++)
1655 {
1656 switch (basicType)
1657 {
1658 case EbtFloat:
1659 tempConstArray[i].setFConst(std::max(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
1660 break;
1661 case EbtInt:
1662 tempConstArray[i].setIConst(std::max(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
1663 break;
1664 case EbtUInt:
1665 tempConstArray[i].setUConst(std::max(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
1666 break;
1667 default:
1668 UNREACHABLE();
1669 break;
1670 }
1671 }
1672 }
1673 break;
1674
Arun Patolebf790422015-05-18 17:53:04 +05301675 case EOpStep:
1676 {
1677 if (basicType == EbtFloat)
1678 {
1679 tempConstArray = new TConstantUnion[maxObjectSize];
1680 for (size_t i = 0; i < maxObjectSize; i++)
1681 tempConstArray[i].setFConst(unionArrays[1][i].getFConst() < unionArrays[0][i].getFConst() ? 0.0f : 1.0f);
1682 }
1683 else
1684 UNREACHABLE();
1685 }
1686 break;
1687
Arun Patole274f0702015-05-05 13:33:30 +05301688 default:
1689 UNREACHABLE();
1690 // TODO: Add constant folding support for other built-in operations that take 2 parameters and not handled above.
1691 return nullptr;
1692 }
1693 }
1694 else if (paramsCount == 3)
1695 {
1696 //
1697 // Ternary built-in
1698 //
1699 switch (op)
1700 {
1701 case EOpClamp:
1702 {
1703 tempConstArray = new TConstantUnion[maxObjectSize];
1704 for (size_t i = 0; i < maxObjectSize; i++)
1705 {
1706 switch (basicType)
1707 {
1708 case EbtFloat:
1709 {
1710 float x = unionArrays[0][i].getFConst();
1711 float min = unionArrays[1][i].getFConst();
1712 float max = unionArrays[2][i].getFConst();
1713 // Results are undefined if min > max.
1714 if (min > max)
1715 tempConstArray[i].setFConst(0.0f);
1716 else
1717 tempConstArray[i].setFConst(gl::clamp(x, min, max));
1718 }
1719 break;
1720 case EbtInt:
1721 {
1722 int x = unionArrays[0][i].getIConst();
1723 int min = unionArrays[1][i].getIConst();
1724 int max = unionArrays[2][i].getIConst();
1725 // Results are undefined if min > max.
1726 if (min > max)
1727 tempConstArray[i].setIConst(0);
1728 else
1729 tempConstArray[i].setIConst(gl::clamp(x, min, max));
1730 }
1731 break;
1732 case EbtUInt:
1733 {
1734 unsigned int x = unionArrays[0][i].getUConst();
1735 unsigned int min = unionArrays[1][i].getUConst();
1736 unsigned int max = unionArrays[2][i].getUConst();
1737 // Results are undefined if min > max.
1738 if (min > max)
1739 tempConstArray[i].setUConst(0u);
1740 else
1741 tempConstArray[i].setUConst(gl::clamp(x, min, max));
1742 }
1743 break;
1744 default:
1745 UNREACHABLE();
1746 break;
1747 }
1748 }
1749 }
1750 break;
1751
Arun Patolebf790422015-05-18 17:53:04 +05301752 case EOpMix:
1753 {
1754 if (basicType == EbtFloat)
1755 {
1756 tempConstArray = new TConstantUnion[maxObjectSize];
1757 for (size_t i = 0; i < maxObjectSize; i++)
1758 {
1759 float x = unionArrays[0][i].getFConst();
1760 float y = unionArrays[1][i].getFConst();
1761 TBasicType type = (*sequence)[2]->getAsTyped()->getType().getBasicType();
1762 if (type == EbtFloat)
1763 {
1764 // Returns the linear blend of x and y, i.e., x * (1 - a) + y * a.
1765 float a = unionArrays[2][i].getFConst();
1766 tempConstArray[i].setFConst(x * (1.0f - a) + y * a);
1767 }
1768 else // 3rd parameter is EbtBool
1769 {
1770 ASSERT(type == EbtBool);
1771 // Selects which vector each returned component comes from.
1772 // For a component of a that is false, the corresponding component of x is returned.
1773 // For a component of a that is true, the corresponding component of y is returned.
1774 bool a = unionArrays[2][i].getBConst();
1775 tempConstArray[i].setFConst(a ? y : x);
1776 }
1777 }
1778 }
1779 else
1780 UNREACHABLE();
1781 }
1782 break;
1783
1784 case EOpSmoothStep:
1785 {
1786 if (basicType == EbtFloat)
1787 {
1788 tempConstArray = new TConstantUnion[maxObjectSize];
1789 for (size_t i = 0; i < maxObjectSize; i++)
1790 {
1791 float edge0 = unionArrays[0][i].getFConst();
1792 float edge1 = unionArrays[1][i].getFConst();
1793 float x = unionArrays[2][i].getFConst();
1794 // Results are undefined if edge0 >= edge1.
1795 if (edge0 >= edge1)
1796 {
1797 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &tempConstArray[i]);
1798 }
1799 else
1800 {
1801 // Returns 0.0 if x <= edge0 and 1.0 if x >= edge1 and performs smooth
1802 // Hermite interpolation between 0 and 1 when edge0 < x < edge1.
1803 float t = gl::clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f);
1804 tempConstArray[i].setFConst(t * t * (3.0f - 2.0f * t));
1805 }
1806 }
1807 }
1808 else
1809 UNREACHABLE();
1810 }
1811 break;
1812
Arun Patole274f0702015-05-05 13:33:30 +05301813 default:
1814 UNREACHABLE();
1815 // TODO: Add constant folding support for other built-in operations that take 3 parameters and not handled above.
1816 return nullptr;
1817 }
1818 }
1819
1820 if (tempConstArray)
1821 {
1822 tempNode = new TIntermConstantUnion(tempConstArray, returnType);
1823 tempNode->setLine(loc);
1824 }
1825 return tempNode;
1826}
1827
1828// static
Jamie Madillb1a85f42014-08-19 15:23:24 -04001829TString TIntermTraverser::hash(const TString &name, ShHashFunction64 hashFunction)
1830{
1831 if (hashFunction == NULL || name.empty())
1832 return name;
1833 khronos_uint64_t number = (*hashFunction)(name.c_str(), name.length());
1834 TStringStream stream;
1835 stream << HASHED_NAME_PREFIX << std::hex << number;
1836 TString hashedName = stream.str();
1837 return hashedName;
1838}
Olli Etuaho853dc1a2014-11-06 17:25:48 +02001839
1840void TIntermTraverser::updateTree()
1841{
Olli Etuahoa6f22092015-05-08 18:31:10 +03001842 for (size_t ii = 0; ii < mInsertions.size(); ++ii)
1843 {
1844 const NodeInsertMultipleEntry &insertion = mInsertions[ii];
1845 ASSERT(insertion.parent);
1846 bool inserted = insertion.parent->insertChildNodes(insertion.position, insertion.insertions);
1847 ASSERT(inserted);
1848 UNUSED_ASSERTION_VARIABLE(inserted);
1849 }
Olli Etuaho853dc1a2014-11-06 17:25:48 +02001850 for (size_t ii = 0; ii < mReplacements.size(); ++ii)
1851 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03001852 const NodeUpdateEntry &replacement = mReplacements[ii];
1853 ASSERT(replacement.parent);
1854 bool replaced = replacement.parent->replaceChildNode(
1855 replacement.original, replacement.replacement);
Olli Etuaho853dc1a2014-11-06 17:25:48 +02001856 ASSERT(replaced);
Olli Etuahod57e0db2015-04-24 15:05:08 +03001857 UNUSED_ASSERTION_VARIABLE(replaced);
Olli Etuaho853dc1a2014-11-06 17:25:48 +02001858
Olli Etuahocd94ef92015-04-16 19:18:10 +03001859 if (!replacement.originalBecomesChildOfReplacement)
Olli Etuaho853dc1a2014-11-06 17:25:48 +02001860 {
1861 // In AST traversing, a parent is visited before its children.
Olli Etuahocd94ef92015-04-16 19:18:10 +03001862 // After we replace a node, if its immediate child is to
Olli Etuaho853dc1a2014-11-06 17:25:48 +02001863 // be replaced, we need to make sure we don't update the replaced
1864 // node; instead, we update the replacement node.
1865 for (size_t jj = ii + 1; jj < mReplacements.size(); ++jj)
1866 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03001867 NodeUpdateEntry &replacement2 = mReplacements[jj];
1868 if (replacement2.parent == replacement.original)
1869 replacement2.parent = replacement.replacement;
Olli Etuaho853dc1a2014-11-06 17:25:48 +02001870 }
1871 }
1872 }
Olli Etuahofc0e2bc2015-04-16 13:39:56 +03001873 for (size_t ii = 0; ii < mMultiReplacements.size(); ++ii)
1874 {
1875 const NodeReplaceWithMultipleEntry &replacement = mMultiReplacements[ii];
1876 ASSERT(replacement.parent);
1877 bool replaced = replacement.parent->replaceChildNodeWithMultiple(
1878 replacement.original, replacement.replacements);
1879 ASSERT(replaced);
Olli Etuahod57e0db2015-04-24 15:05:08 +03001880 UNUSED_ASSERTION_VARIABLE(replaced);
Olli Etuahofc0e2bc2015-04-16 13:39:56 +03001881 }
Olli Etuaho853dc1a2014-11-06 17:25:48 +02001882}