blob: 4f441aec2db38a05fee43be522c9fcaf91586d10 [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 }
Jamie Madill2f4823b2015-06-03 12:39:22 +00001166 else if (op == EOpAny || op == EOpAll)
Arun Patole9d0b1f92015-05-20 14:27:17 +05301167 {
1168 // Do operations where the return type is different from the operand type.
1169
Jamie Madill2f4823b2015-06-03 12:39:22 +00001170 TType returnType(EbtBool, EbpUndefined, EvqConst);
Arun Patole9d0b1f92015-05-20 14:27:17 +05301171 TConstantUnion *tempConstArray = nullptr;
Jamie Madill2f4823b2015-06-03 12:39:22 +00001172 if (op == EOpAny)
Arun Patole9d0b1f92015-05-20 14:27:17 +05301173 {
1174 if (getType().getBasicType() == EbtBool)
1175 {
1176 tempConstArray = new TConstantUnion();
1177 tempConstArray->setBConst(false);
1178 for (size_t i = 0; i < objectSize; i++)
1179 {
1180 if (unionArray[i].getBConst())
1181 {
1182 tempConstArray->setBConst(true);
1183 break;
1184 }
1185 }
1186 }
1187 else
1188 {
Jamie Madill2f4823b2015-06-03 12:39:22 +00001189 infoSink.info.message(
1190 EPrefixInternalError, getLine(),
1191 "Unary operation not folded into constant");
Arun Patole9d0b1f92015-05-20 14:27:17 +05301192 return nullptr;
1193 }
Jamie Madill2f4823b2015-06-03 12:39:22 +00001194 }
1195 else if (op == EOpAll)
1196 {
Arun Patole9d0b1f92015-05-20 14:27:17 +05301197 if (getType().getBasicType() == EbtBool)
1198 {
1199 tempConstArray = new TConstantUnion();
1200 tempConstArray->setBConst(true);
1201 for (size_t i = 0; i < objectSize; i++)
1202 {
1203 if (!unionArray[i].getBConst())
1204 {
1205 tempConstArray->setBConst(false);
1206 break;
1207 }
1208 }
1209 }
1210 else
1211 {
Jamie Madill2f4823b2015-06-03 12:39:22 +00001212 infoSink.info.message(
1213 EPrefixInternalError, getLine(),
1214 "Unary operation not folded into constant");
Arun Patole9d0b1f92015-05-20 14:27:17 +05301215 return nullptr;
1216 }
1217 }
1218 TIntermConstantUnion *tempNode = new TIntermConstantUnion(tempConstArray, returnType);
1219 tempNode->setLine(getLine());
1220 return tempNode;
1221 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04001222 else
1223 {
1224 //
Arun Patole9d0b1f92015-05-20 14:27:17 +05301225 // Do unary operations where the return type is the same as operand type.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001226 //
1227 TIntermConstantUnion *newNode = 0;
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001228 TConstantUnion* tempConstArray = new TConstantUnion[objectSize];
Jamie Madillb1a85f42014-08-19 15:23:24 -04001229 for (size_t i = 0; i < objectSize; i++)
1230 {
1231 switch(op)
1232 {
1233 case EOpNegative:
1234 switch (getType().getBasicType())
1235 {
1236 case EbtFloat:
1237 tempConstArray[i].setFConst(-unionArray[i].getFConst());
1238 break;
1239 case EbtInt:
1240 tempConstArray[i].setIConst(-unionArray[i].getIConst());
1241 break;
1242 case EbtUInt:
1243 tempConstArray[i].setUConst(static_cast<unsigned int>(
1244 -static_cast<int>(unionArray[i].getUConst())));
1245 break;
1246 default:
1247 infoSink.info.message(
1248 EPrefixInternalError, getLine(),
1249 "Unary operation not folded into constant");
Arun Patolefddc2112015-04-22 13:28:10 +05301250 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001251 }
1252 break;
1253
Zhenyao Mode1e00e2014-10-09 16:55:32 -07001254 case EOpPositive:
1255 switch (getType().getBasicType())
1256 {
1257 case EbtFloat:
1258 tempConstArray[i].setFConst(unionArray[i].getFConst());
1259 break;
1260 case EbtInt:
1261 tempConstArray[i].setIConst(unionArray[i].getIConst());
1262 break;
1263 case EbtUInt:
1264 tempConstArray[i].setUConst(static_cast<unsigned int>(
1265 static_cast<int>(unionArray[i].getUConst())));
1266 break;
1267 default:
1268 infoSink.info.message(
1269 EPrefixInternalError, getLine(),
1270 "Unary operation not folded into constant");
Arun Patolefddc2112015-04-22 13:28:10 +05301271 return nullptr;
Zhenyao Mode1e00e2014-10-09 16:55:32 -07001272 }
1273 break;
1274
Jamie Madillb1a85f42014-08-19 15:23:24 -04001275 case EOpLogicalNot:
1276 // this code is written for possible future use,
1277 // will not get executed currently
1278 switch (getType().getBasicType())
1279 {
1280 case EbtBool:
1281 tempConstArray[i].setBConst(!unionArray[i].getBConst());
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
Olli Etuaho31b5fc62015-01-16 12:13:36 +02001291 case EOpBitwiseNot:
1292 switch (getType().getBasicType())
1293 {
1294 case EbtInt:
1295 tempConstArray[i].setIConst(~unionArray[i].getIConst());
1296 break;
1297 case EbtUInt:
1298 tempConstArray[i].setUConst(~unionArray[i].getUConst());
1299 break;
1300 default:
1301 infoSink.info.message(
1302 EPrefixInternalError, getLine(),
1303 "Unary operation not folded into constant");
Arun Patolefddc2112015-04-22 13:28:10 +05301304 return nullptr;
Olli Etuaho31b5fc62015-01-16 12:13:36 +02001305 }
1306 break;
1307
Arun Patole9dea48f2015-04-02 11:45:09 +05301308 case EOpRadians:
1309 if (getType().getBasicType() == EbtFloat)
1310 {
1311 tempConstArray[i].setFConst(kDegreesToRadiansMultiplier * unionArray[i].getFConst());
1312 break;
1313 }
1314 infoSink.info.message(
1315 EPrefixInternalError, getLine(),
1316 "Unary operation not folded into constant");
1317 return nullptr;
1318
1319 case EOpDegrees:
1320 if (getType().getBasicType() == EbtFloat)
1321 {
1322 tempConstArray[i].setFConst(kRadiansToDegreesMultiplier * unionArray[i].getFConst());
1323 break;
1324 }
1325 infoSink.info.message(
1326 EPrefixInternalError, getLine(),
1327 "Unary operation not folded into constant");
1328 return nullptr;
1329
1330 case EOpSin:
1331 if (!foldFloatTypeUnary(unionArray[i], &sinf, infoSink, &tempConstArray[i]))
1332 return nullptr;
1333 break;
1334
1335 case EOpCos:
1336 if (!foldFloatTypeUnary(unionArray[i], &cosf, infoSink, &tempConstArray[i]))
1337 return nullptr;
1338 break;
1339
1340 case EOpTan:
1341 if (!foldFloatTypeUnary(unionArray[i], &tanf, infoSink, &tempConstArray[i]))
1342 return nullptr;
1343 break;
1344
1345 case EOpAsin:
1346 // For asin(x), results are undefined if |x| > 1, we are choosing to set result to 0.
1347 if (getType().getBasicType() == EbtFloat && fabsf(unionArray[i].getFConst()) > 1.0f)
Arun Patole081c3f22015-05-25 15:43:35 +05301348 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &tempConstArray[i]);
Arun Patole9dea48f2015-04-02 11:45:09 +05301349 else if (!foldFloatTypeUnary(unionArray[i], &asinf, infoSink, &tempConstArray[i]))
1350 return nullptr;
1351 break;
1352
1353 case EOpAcos:
1354 // For acos(x), results are undefined if |x| > 1, we are choosing to set result to 0.
1355 if (getType().getBasicType() == EbtFloat && fabsf(unionArray[i].getFConst()) > 1.0f)
Arun Patole081c3f22015-05-25 15:43:35 +05301356 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &tempConstArray[i]);
Arun Patole9dea48f2015-04-02 11:45:09 +05301357 else if (!foldFloatTypeUnary(unionArray[i], &acosf, infoSink, &tempConstArray[i]))
1358 return nullptr;
1359 break;
1360
1361 case EOpAtan:
1362 if (!foldFloatTypeUnary(unionArray[i], &atanf, infoSink, &tempConstArray[i]))
1363 return nullptr;
1364 break;
1365
1366 case EOpSinh:
1367 if (!foldFloatTypeUnary(unionArray[i], &sinhf, infoSink, &tempConstArray[i]))
1368 return nullptr;
1369 break;
1370
1371 case EOpCosh:
1372 if (!foldFloatTypeUnary(unionArray[i], &coshf, infoSink, &tempConstArray[i]))
1373 return nullptr;
1374 break;
1375
1376 case EOpTanh:
1377 if (!foldFloatTypeUnary(unionArray[i], &tanhf, infoSink, &tempConstArray[i]))
1378 return nullptr;
1379 break;
1380
1381 case EOpAsinh:
1382 if (!foldFloatTypeUnary(unionArray[i], &asinhf, infoSink, &tempConstArray[i]))
1383 return nullptr;
1384 break;
1385
1386 case EOpAcosh:
1387 // For acosh(x), results are undefined if x < 1, we are choosing to set result to 0.
1388 if (getType().getBasicType() == EbtFloat && unionArray[i].getFConst() < 1.0f)
Arun Patole081c3f22015-05-25 15:43:35 +05301389 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &tempConstArray[i]);
Arun Patole9dea48f2015-04-02 11:45:09 +05301390 else if (!foldFloatTypeUnary(unionArray[i], &acoshf, infoSink, &tempConstArray[i]))
1391 return nullptr;
1392 break;
1393
1394 case EOpAtanh:
1395 // For atanh(x), results are undefined if |x| >= 1, we are choosing to set result to 0.
1396 if (getType().getBasicType() == EbtFloat && fabsf(unionArray[i].getFConst()) >= 1.0f)
Arun Patole081c3f22015-05-25 15:43:35 +05301397 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &tempConstArray[i]);
Arun Patole9dea48f2015-04-02 11:45:09 +05301398 else if (!foldFloatTypeUnary(unionArray[i], &atanhf, infoSink, &tempConstArray[i]))
1399 return nullptr;
1400 break;
1401
Arun Patole97dc22e2015-04-06 17:35:38 +05301402 case EOpAbs:
1403 switch (getType().getBasicType())
1404 {
1405 case EbtFloat:
1406 tempConstArray[i].setFConst(fabsf(unionArray[i].getFConst()));
1407 break;
1408 case EbtInt:
1409 tempConstArray[i].setIConst(abs(unionArray[i].getIConst()));
1410 break;
1411 default:
1412 infoSink.info.message(
1413 EPrefixInternalError, getLine(),
1414 "Unary operation not folded into constant");
1415 return nullptr;
1416 }
1417 break;
1418
1419 case EOpSign:
1420 switch (getType().getBasicType())
1421 {
1422 case EbtFloat:
1423 {
1424 float fConst = unionArray[i].getFConst();
1425 float fResult = 0.0f;
1426 if (fConst > 0.0f)
1427 fResult = 1.0f;
1428 else if (fConst < 0.0f)
1429 fResult = -1.0f;
1430 tempConstArray[i].setFConst(fResult);
1431 }
1432 break;
1433 case EbtInt:
1434 {
1435 int iConst = unionArray[i].getIConst();
1436 int iResult = 0;
1437 if (iConst > 0)
1438 iResult = 1;
1439 else if (iConst < 0)
1440 iResult = -1;
1441 tempConstArray[i].setIConst(iResult);
1442 }
1443 break;
1444 default:
1445 infoSink.info.message(
1446 EPrefixInternalError, getLine(),
1447 "Unary operation not folded into constant");
1448 return nullptr;
1449 }
1450 break;
1451
1452 case EOpFloor:
1453 if (!foldFloatTypeUnary(unionArray[i], &floorf, infoSink, &tempConstArray[i]))
1454 return nullptr;
1455 break;
1456
1457 case EOpTrunc:
1458 if (!foldFloatTypeUnary(unionArray[i], &truncf, infoSink, &tempConstArray[i]))
1459 return nullptr;
1460 break;
1461
1462 case EOpRound:
1463 if (!foldFloatTypeUnary(unionArray[i], &roundf, infoSink, &tempConstArray[i]))
1464 return nullptr;
1465 break;
1466
1467 case EOpRoundEven:
1468 if (getType().getBasicType() == EbtFloat)
1469 {
1470 float x = unionArray[i].getFConst();
1471 float result;
1472 float fractPart = modff(x, &result);
1473 if (fabsf(fractPart) == 0.5f)
1474 result = 2.0f * roundf(x / 2.0f);
1475 else
1476 result = roundf(x);
1477 tempConstArray[i].setFConst(result);
1478 break;
1479 }
1480 infoSink.info.message(
1481 EPrefixInternalError, getLine(),
1482 "Unary operation not folded into constant");
1483 return nullptr;
1484
1485 case EOpCeil:
1486 if (!foldFloatTypeUnary(unionArray[i], &ceilf, infoSink, &tempConstArray[i]))
1487 return nullptr;
1488 break;
1489
1490 case EOpFract:
1491 if (getType().getBasicType() == EbtFloat)
1492 {
1493 float x = unionArray[i].getFConst();
1494 tempConstArray[i].setFConst(x - floorf(x));
1495 break;
1496 }
1497 infoSink.info.message(
1498 EPrefixInternalError, getLine(),
1499 "Unary operation not folded into constant");
1500 return nullptr;
1501
Arun Patole28eb65e2015-04-06 17:29:48 +05301502 case EOpExp:
1503 if (!foldFloatTypeUnary(unionArray[i], &expf, infoSink, &tempConstArray[i]))
1504 return nullptr;
1505 break;
1506
1507 case EOpLog:
1508 // For log(x), results are undefined if x <= 0, we are choosing to set result to 0.
1509 if (getType().getBasicType() == EbtFloat && unionArray[i].getFConst() <= 0.0f)
Arun Patole081c3f22015-05-25 15:43:35 +05301510 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &tempConstArray[i]);
Arun Patole28eb65e2015-04-06 17:29:48 +05301511 else if (!foldFloatTypeUnary(unionArray[i], &logf, infoSink, &tempConstArray[i]))
1512 return nullptr;
1513 break;
1514
1515 case EOpExp2:
1516 if (!foldFloatTypeUnary(unionArray[i], &exp2f, infoSink, &tempConstArray[i]))
1517 return nullptr;
1518 break;
1519
1520 case EOpLog2:
1521 // For log2(x), results are undefined if x <= 0, we are choosing to set result to 0.
1522 // And log2f is not available on some plarforms like old android, so just using log(x)/log(2) here.
1523 if (getType().getBasicType() == EbtFloat && unionArray[i].getFConst() <= 0.0f)
Arun Patole081c3f22015-05-25 15:43:35 +05301524 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &tempConstArray[i]);
Arun Patole28eb65e2015-04-06 17:29:48 +05301525 else if (!foldFloatTypeUnary(unionArray[i], &logf, infoSink, &tempConstArray[i]))
1526 return nullptr;
1527 else
1528 tempConstArray[i].setFConst(tempConstArray[i].getFConst() / logf(2.0f));
1529 break;
1530
1531 case EOpSqrt:
1532 // For sqrt(x), results are undefined if x < 0, we are choosing to set result to 0.
1533 if (getType().getBasicType() == EbtFloat && unionArray[i].getFConst() < 0.0f)
Arun Patole081c3f22015-05-25 15:43:35 +05301534 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &tempConstArray[i]);
Arun Patole28eb65e2015-04-06 17:29:48 +05301535 else if (!foldFloatTypeUnary(unionArray[i], &sqrtf, infoSink, &tempConstArray[i]))
1536 return nullptr;
1537 break;
1538
1539 case EOpInverseSqrt:
1540 // There is no stdlib built-in function equavalent for GLES built-in inversesqrt(),
1541 // so getting the square root first using builtin function sqrt() and then taking its inverse.
1542 // Also, for inversesqrt(x), results are undefined if x <= 0, we are choosing to set result to 0.
1543 if (getType().getBasicType() == EbtFloat && unionArray[i].getFConst() <= 0.0f)
Arun Patole081c3f22015-05-25 15:43:35 +05301544 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &tempConstArray[i]);
Arun Patole28eb65e2015-04-06 17:29:48 +05301545 else if (!foldFloatTypeUnary(unionArray[i], &sqrtf, infoSink, &tempConstArray[i]))
1546 return nullptr;
1547 else
1548 tempConstArray[i].setFConst(1.0f / tempConstArray[i].getFConst());
1549 break;
1550
Arun Patole9d0b1f92015-05-20 14:27:17 +05301551 case EOpVectorLogicalNot:
1552 if (getType().getBasicType() == EbtBool)
1553 {
1554 tempConstArray[i].setBConst(!unionArray[i].getBConst());
1555 break;
1556 }
1557 infoSink.info.message(
1558 EPrefixInternalError, getLine(),
1559 "Unary operation not folded into constant");
1560 return nullptr;
1561
Jamie Madillb1a85f42014-08-19 15:23:24 -04001562 default:
Arun Patolefddc2112015-04-22 13:28:10 +05301563 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001564 }
1565 }
1566 newNode = new TIntermConstantUnion(tempConstArray, getType());
1567 newNode->setLine(getLine());
1568 return newNode;
1569 }
1570}
1571
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001572bool TIntermConstantUnion::foldFloatTypeUnary(const TConstantUnion &parameter, FloatTypeUnaryFunc builtinFunc,
1573 TInfoSink &infoSink, TConstantUnion *result) const
Arun Patole9dea48f2015-04-02 11:45:09 +05301574{
1575 ASSERT(builtinFunc);
1576
1577 if (getType().getBasicType() == EbtFloat)
1578 {
1579 result->setFConst(builtinFunc(parameter.getFConst()));
1580 return true;
1581 }
1582
1583 infoSink.info.message(
1584 EPrefixInternalError, getLine(),
1585 "Unary operation not folded into constant");
1586 return false;
1587}
1588
Jamie Madillb1a85f42014-08-19 15:23:24 -04001589// static
Arun Patolebf790422015-05-18 17:53:04 +05301590TIntermTyped *TIntermConstantUnion::FoldAggregateBuiltIn(TOperator op, TIntermAggregate *aggregate, TInfoSink &infoSink)
Arun Patole274f0702015-05-05 13:33:30 +05301591{
1592 TIntermSequence *sequence = aggregate->getSequence();
1593 unsigned int paramsCount = sequence->size();
1594 std::vector<TConstantUnion *> unionArrays(paramsCount);
1595 std::vector<size_t> objectSizes(paramsCount);
1596 TType *maxSizeType = nullptr;
1597 TBasicType basicType = EbtVoid;
1598 TSourceLoc loc;
1599 for (unsigned int i = 0; i < paramsCount; i++)
1600 {
1601 TIntermConstantUnion *paramConstant = (*sequence)[i]->getAsConstantUnion();
1602 // Make sure that all params are constant before actual constant folding.
1603 if (!paramConstant)
1604 return nullptr;
1605
1606 if (i == 0)
1607 {
1608 basicType = paramConstant->getType().getBasicType();
1609 loc = paramConstant->getLine();
1610 }
1611 unionArrays[i] = paramConstant->getUnionArrayPointer();
1612 objectSizes[i] = paramConstant->getType().getObjectSize();
1613 if (maxSizeType == nullptr || (objectSizes[i] >= maxSizeType->getObjectSize()))
1614 maxSizeType = paramConstant->getTypePointer();
1615 }
1616
1617 size_t maxObjectSize = maxSizeType->getObjectSize();
1618 for (unsigned int i = 0; i < paramsCount; i++)
1619 if (objectSizes[i] != maxObjectSize)
1620 unionArrays[i] = Vectorize(*unionArrays[i], maxObjectSize);
1621
1622 TConstantUnion *tempConstArray = nullptr;
1623 TIntermConstantUnion *tempNode = nullptr;
1624 TType returnType = *maxSizeType;
1625 if (paramsCount == 2)
1626 {
1627 //
1628 // Binary built-in
1629 //
1630 switch (op)
1631 {
Arun Patolebf790422015-05-18 17:53:04 +05301632 case EOpAtan:
1633 {
1634 if (basicType == EbtFloat)
1635 {
1636 tempConstArray = new TConstantUnion[maxObjectSize];
1637 for (size_t i = 0; i < maxObjectSize; i++)
1638 {
1639 float y = unionArrays[0][i].getFConst();
1640 float x = unionArrays[1][i].getFConst();
1641 // Results are undefined if x and y are both 0.
1642 if (x == 0.0f && y == 0.0f)
1643 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &tempConstArray[i]);
1644 else
1645 tempConstArray[i].setFConst(atan2f(y, x));
1646 }
1647 }
1648 else
1649 UNREACHABLE();
1650 }
1651 break;
1652
1653 case EOpPow:
1654 {
1655 if (basicType == EbtFloat)
1656 {
1657 tempConstArray = new TConstantUnion[maxObjectSize];
1658 for (size_t i = 0; i < maxObjectSize; i++)
1659 {
1660 float x = unionArrays[0][i].getFConst();
1661 float y = unionArrays[1][i].getFConst();
1662 // Results are undefined if x < 0.
1663 // Results are undefined if x = 0 and y <= 0.
1664 if (x < 0.0f)
1665 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &tempConstArray[i]);
1666 else if (x == 0.0f && y <= 0.0f)
1667 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &tempConstArray[i]);
1668 else
1669 tempConstArray[i].setFConst(powf(x, y));
1670 }
1671 }
1672 else
1673 UNREACHABLE();
1674 }
1675 break;
1676
1677 case EOpMod:
1678 {
1679 if (basicType == EbtFloat)
1680 {
1681 tempConstArray = new TConstantUnion[maxObjectSize];
1682 for (size_t i = 0; i < maxObjectSize; i++)
1683 {
1684 float x = unionArrays[0][i].getFConst();
1685 float y = unionArrays[1][i].getFConst();
1686 tempConstArray[i].setFConst(x - y * floorf(x / y));
1687 }
1688 }
1689 else
1690 UNREACHABLE();
1691 }
1692 break;
1693
Arun Patole274f0702015-05-05 13:33:30 +05301694 case EOpMin:
1695 {
1696 tempConstArray = new TConstantUnion[maxObjectSize];
1697 for (size_t i = 0; i < maxObjectSize; i++)
1698 {
1699 switch (basicType)
1700 {
1701 case EbtFloat:
1702 tempConstArray[i].setFConst(std::min(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
1703 break;
1704 case EbtInt:
1705 tempConstArray[i].setIConst(std::min(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
1706 break;
1707 case EbtUInt:
1708 tempConstArray[i].setUConst(std::min(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
1709 break;
1710 default:
1711 UNREACHABLE();
1712 break;
1713 }
1714 }
1715 }
1716 break;
1717
1718 case EOpMax:
1719 {
1720 tempConstArray = new TConstantUnion[maxObjectSize];
1721 for (size_t i = 0; i < maxObjectSize; i++)
1722 {
1723 switch (basicType)
1724 {
1725 case EbtFloat:
1726 tempConstArray[i].setFConst(std::max(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
1727 break;
1728 case EbtInt:
1729 tempConstArray[i].setIConst(std::max(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
1730 break;
1731 case EbtUInt:
1732 tempConstArray[i].setUConst(std::max(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
1733 break;
1734 default:
1735 UNREACHABLE();
1736 break;
1737 }
1738 }
1739 }
1740 break;
1741
Arun Patolebf790422015-05-18 17:53:04 +05301742 case EOpStep:
1743 {
1744 if (basicType == EbtFloat)
1745 {
1746 tempConstArray = new TConstantUnion[maxObjectSize];
1747 for (size_t i = 0; i < maxObjectSize; i++)
1748 tempConstArray[i].setFConst(unionArrays[1][i].getFConst() < unionArrays[0][i].getFConst() ? 0.0f : 1.0f);
1749 }
1750 else
1751 UNREACHABLE();
1752 }
1753 break;
1754
Arun Patole9d0b1f92015-05-20 14:27:17 +05301755 case EOpLessThan:
1756 {
1757 tempConstArray = new TConstantUnion[maxObjectSize];
1758 for (size_t i = 0; i < maxObjectSize; i++)
1759 {
1760 switch (basicType)
1761 {
1762 case EbtFloat:
1763 tempConstArray[i].setBConst(unionArrays[0][i].getFConst() < unionArrays[1][i].getFConst());
1764 break;
1765 case EbtInt:
1766 tempConstArray[i].setBConst(unionArrays[0][i].getIConst() < unionArrays[1][i].getIConst());
1767 break;
1768 case EbtUInt:
1769 tempConstArray[i].setBConst(unionArrays[0][i].getUConst() < unionArrays[1][i].getUConst());
1770 break;
1771 default:
1772 UNREACHABLE();
1773 break;
1774 }
1775 }
1776 }
1777 break;
1778
1779 case EOpLessThanEqual:
1780 {
1781 tempConstArray = new TConstantUnion[maxObjectSize];
1782 for (size_t i = 0; i < maxObjectSize; i++)
1783 {
1784 switch (basicType)
1785 {
1786 case EbtFloat:
1787 tempConstArray[i].setBConst(unionArrays[0][i].getFConst() <= unionArrays[1][i].getFConst());
1788 break;
1789 case EbtInt:
1790 tempConstArray[i].setBConst(unionArrays[0][i].getIConst() <= unionArrays[1][i].getIConst());
1791 break;
1792 case EbtUInt:
1793 tempConstArray[i].setBConst(unionArrays[0][i].getUConst() <= unionArrays[1][i].getUConst());
1794 break;
1795 default:
1796 UNREACHABLE();
1797 break;
1798 }
1799 }
1800 }
1801 break;
1802
1803 case EOpGreaterThan:
1804 {
1805 tempConstArray = new TConstantUnion[maxObjectSize];
1806 for (size_t i = 0; i < maxObjectSize; i++)
1807 {
1808 switch (basicType)
1809 {
1810 case EbtFloat:
1811 tempConstArray[i].setBConst(unionArrays[0][i].getFConst() > unionArrays[1][i].getFConst());
1812 break;
1813 case EbtInt:
1814 tempConstArray[i].setBConst(unionArrays[0][i].getIConst() > unionArrays[1][i].getIConst());
1815 break;
1816 case EbtUInt:
1817 tempConstArray[i].setBConst(unionArrays[0][i].getUConst() > unionArrays[1][i].getUConst());
1818 break;
1819 default:
1820 UNREACHABLE();
1821 break;
1822 }
1823 }
1824 }
1825 break;
1826
1827 case EOpGreaterThanEqual:
1828 {
1829 tempConstArray = new TConstantUnion[maxObjectSize];
1830 for (size_t i = 0; i < maxObjectSize; i++)
1831 {
1832 switch (basicType)
1833 {
1834 case EbtFloat:
1835 tempConstArray[i].setBConst(unionArrays[0][i].getFConst() >= unionArrays[1][i].getFConst());
1836 break;
1837 case EbtInt:
1838 tempConstArray[i].setBConst(unionArrays[0][i].getIConst() >= unionArrays[1][i].getIConst());
1839 break;
1840 case EbtUInt:
1841 tempConstArray[i].setBConst(unionArrays[0][i].getUConst() >= unionArrays[1][i].getUConst());
1842 break;
1843 default:
1844 UNREACHABLE();
1845 break;
1846 }
1847 }
1848 }
1849 break;
1850
1851 case EOpVectorEqual:
1852 {
1853 tempConstArray = new TConstantUnion[maxObjectSize];
1854 for (size_t i = 0; i < maxObjectSize; i++)
1855 {
1856 switch (basicType)
1857 {
1858 case EbtFloat:
1859 tempConstArray[i].setBConst(unionArrays[0][i].getFConst() == unionArrays[1][i].getFConst());
1860 break;
1861 case EbtInt:
1862 tempConstArray[i].setBConst(unionArrays[0][i].getIConst() == unionArrays[1][i].getIConst());
1863 break;
1864 case EbtUInt:
1865 tempConstArray[i].setBConst(unionArrays[0][i].getUConst() == unionArrays[1][i].getUConst());
1866 break;
1867 case EbtBool:
1868 tempConstArray[i].setBConst(unionArrays[0][i].getBConst() == unionArrays[1][i].getBConst());
1869 break;
1870 default:
1871 UNREACHABLE();
1872 break;
1873 }
1874 }
1875 }
1876 break;
1877
1878 case EOpVectorNotEqual:
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 case EbtBool:
1895 tempConstArray[i].setBConst(unionArrays[0][i].getBConst() != unionArrays[1][i].getBConst());
1896 break;
1897 default:
1898 UNREACHABLE();
1899 break;
1900 }
1901 }
1902 }
1903 break;
1904
Arun Patole274f0702015-05-05 13:33:30 +05301905 default:
1906 UNREACHABLE();
1907 // TODO: Add constant folding support for other built-in operations that take 2 parameters and not handled above.
1908 return nullptr;
1909 }
1910 }
1911 else if (paramsCount == 3)
1912 {
1913 //
1914 // Ternary built-in
1915 //
1916 switch (op)
1917 {
1918 case EOpClamp:
1919 {
1920 tempConstArray = new TConstantUnion[maxObjectSize];
1921 for (size_t i = 0; i < maxObjectSize; i++)
1922 {
1923 switch (basicType)
1924 {
1925 case EbtFloat:
1926 {
1927 float x = unionArrays[0][i].getFConst();
1928 float min = unionArrays[1][i].getFConst();
1929 float max = unionArrays[2][i].getFConst();
1930 // Results are undefined if min > max.
1931 if (min > max)
Arun Patole081c3f22015-05-25 15:43:35 +05301932 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &tempConstArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05301933 else
1934 tempConstArray[i].setFConst(gl::clamp(x, min, max));
1935 }
1936 break;
1937 case EbtInt:
1938 {
1939 int x = unionArrays[0][i].getIConst();
1940 int min = unionArrays[1][i].getIConst();
1941 int max = unionArrays[2][i].getIConst();
1942 // Results are undefined if min > max.
1943 if (min > max)
Arun Patole081c3f22015-05-25 15:43:35 +05301944 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &tempConstArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05301945 else
1946 tempConstArray[i].setIConst(gl::clamp(x, min, max));
1947 }
1948 break;
1949 case EbtUInt:
1950 {
1951 unsigned int x = unionArrays[0][i].getUConst();
1952 unsigned int min = unionArrays[1][i].getUConst();
1953 unsigned int max = unionArrays[2][i].getUConst();
1954 // Results are undefined if min > max.
1955 if (min > max)
Arun Patole081c3f22015-05-25 15:43:35 +05301956 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &tempConstArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05301957 else
1958 tempConstArray[i].setUConst(gl::clamp(x, min, max));
1959 }
1960 break;
1961 default:
1962 UNREACHABLE();
1963 break;
1964 }
1965 }
1966 }
1967 break;
1968
Arun Patolebf790422015-05-18 17:53:04 +05301969 case EOpMix:
1970 {
1971 if (basicType == EbtFloat)
1972 {
1973 tempConstArray = new TConstantUnion[maxObjectSize];
1974 for (size_t i = 0; i < maxObjectSize; i++)
1975 {
1976 float x = unionArrays[0][i].getFConst();
1977 float y = unionArrays[1][i].getFConst();
1978 TBasicType type = (*sequence)[2]->getAsTyped()->getType().getBasicType();
1979 if (type == EbtFloat)
1980 {
1981 // Returns the linear blend of x and y, i.e., x * (1 - a) + y * a.
1982 float a = unionArrays[2][i].getFConst();
1983 tempConstArray[i].setFConst(x * (1.0f - a) + y * a);
1984 }
1985 else // 3rd parameter is EbtBool
1986 {
1987 ASSERT(type == EbtBool);
1988 // Selects which vector each returned component comes from.
1989 // For a component of a that is false, the corresponding component of x is returned.
1990 // For a component of a that is true, the corresponding component of y is returned.
1991 bool a = unionArrays[2][i].getBConst();
1992 tempConstArray[i].setFConst(a ? y : x);
1993 }
1994 }
1995 }
1996 else
1997 UNREACHABLE();
1998 }
1999 break;
2000
2001 case EOpSmoothStep:
2002 {
2003 if (basicType == EbtFloat)
2004 {
2005 tempConstArray = new TConstantUnion[maxObjectSize];
2006 for (size_t i = 0; i < maxObjectSize; i++)
2007 {
2008 float edge0 = unionArrays[0][i].getFConst();
2009 float edge1 = unionArrays[1][i].getFConst();
2010 float x = unionArrays[2][i].getFConst();
2011 // Results are undefined if edge0 >= edge1.
2012 if (edge0 >= edge1)
2013 {
2014 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &tempConstArray[i]);
2015 }
2016 else
2017 {
2018 // Returns 0.0 if x <= edge0 and 1.0 if x >= edge1 and performs smooth
2019 // Hermite interpolation between 0 and 1 when edge0 < x < edge1.
2020 float t = gl::clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f);
2021 tempConstArray[i].setFConst(t * t * (3.0f - 2.0f * t));
2022 }
2023 }
2024 }
2025 else
2026 UNREACHABLE();
2027 }
2028 break;
2029
Arun Patole274f0702015-05-05 13:33:30 +05302030 default:
2031 UNREACHABLE();
2032 // TODO: Add constant folding support for other built-in operations that take 3 parameters and not handled above.
2033 return nullptr;
2034 }
2035 }
2036
2037 if (tempConstArray)
2038 {
2039 tempNode = new TIntermConstantUnion(tempConstArray, returnType);
2040 tempNode->setLine(loc);
2041 }
2042 return tempNode;
2043}
2044
2045// static
Jamie Madillb1a85f42014-08-19 15:23:24 -04002046TString TIntermTraverser::hash(const TString &name, ShHashFunction64 hashFunction)
2047{
2048 if (hashFunction == NULL || name.empty())
2049 return name;
2050 khronos_uint64_t number = (*hashFunction)(name.c_str(), name.length());
2051 TStringStream stream;
2052 stream << HASHED_NAME_PREFIX << std::hex << number;
2053 TString hashedName = stream.str();
2054 return hashedName;
2055}
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002056
2057void TIntermTraverser::updateTree()
2058{
Olli Etuahoa6f22092015-05-08 18:31:10 +03002059 for (size_t ii = 0; ii < mInsertions.size(); ++ii)
2060 {
2061 const NodeInsertMultipleEntry &insertion = mInsertions[ii];
2062 ASSERT(insertion.parent);
2063 bool inserted = insertion.parent->insertChildNodes(insertion.position, insertion.insertions);
2064 ASSERT(inserted);
2065 UNUSED_ASSERTION_VARIABLE(inserted);
2066 }
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002067 for (size_t ii = 0; ii < mReplacements.size(); ++ii)
2068 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03002069 const NodeUpdateEntry &replacement = mReplacements[ii];
2070 ASSERT(replacement.parent);
2071 bool replaced = replacement.parent->replaceChildNode(
2072 replacement.original, replacement.replacement);
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002073 ASSERT(replaced);
Olli Etuahod57e0db2015-04-24 15:05:08 +03002074 UNUSED_ASSERTION_VARIABLE(replaced);
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002075
Olli Etuahocd94ef92015-04-16 19:18:10 +03002076 if (!replacement.originalBecomesChildOfReplacement)
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002077 {
2078 // In AST traversing, a parent is visited before its children.
Olli Etuahocd94ef92015-04-16 19:18:10 +03002079 // After we replace a node, if its immediate child is to
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002080 // be replaced, we need to make sure we don't update the replaced
2081 // node; instead, we update the replacement node.
2082 for (size_t jj = ii + 1; jj < mReplacements.size(); ++jj)
2083 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03002084 NodeUpdateEntry &replacement2 = mReplacements[jj];
2085 if (replacement2.parent == replacement.original)
2086 replacement2.parent = replacement.replacement;
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002087 }
2088 }
2089 }
Olli Etuahofc0e2bc2015-04-16 13:39:56 +03002090 for (size_t ii = 0; ii < mMultiReplacements.size(); ++ii)
2091 {
2092 const NodeReplaceWithMultipleEntry &replacement = mMultiReplacements[ii];
2093 ASSERT(replacement.parent);
2094 bool replaced = replacement.parent->replaceChildNodeWithMultiple(
2095 replacement.original, replacement.replacements);
2096 ASSERT(replaced);
Olli Etuahod57e0db2015-04-24 15:05:08 +03002097 UNUSED_ASSERTION_VARIABLE(replaced);
Olli Etuahofc0e2bc2015-04-16 13:39:56 +03002098 }
Olli Etuahod4f303e2015-05-20 17:09:06 +03002099
2100 mInsertions.clear();
2101 mReplacements.clear();
2102 mMultiReplacements.clear();
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002103}