blob: 5319bc744f275df20cfca7ecd5dfd2dfc9028b5c [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
Olli Etuaho8f76bcc2015-06-02 13:54:20 +0300367bool TIntermOperator::isMultiplication() const
368{
369 switch (mOp)
370 {
371 case EOpMul:
372 case EOpMatrixTimesMatrix:
373 case EOpMatrixTimesVector:
374 case EOpMatrixTimesScalar:
375 case EOpVectorTimesMatrix:
376 case EOpVectorTimesScalar:
377 return true;
378 default:
379 return false;
380 }
381}
382
Jamie Madillb1a85f42014-08-19 15:23:24 -0400383//
384// returns true if the operator is for one of the constructors
385//
386bool TIntermOperator::isConstructor() const
387{
388 switch (mOp)
389 {
390 case EOpConstructVec2:
391 case EOpConstructVec3:
392 case EOpConstructVec4:
393 case EOpConstructMat2:
394 case EOpConstructMat3:
395 case EOpConstructMat4:
396 case EOpConstructFloat:
397 case EOpConstructIVec2:
398 case EOpConstructIVec3:
399 case EOpConstructIVec4:
400 case EOpConstructInt:
401 case EOpConstructUVec2:
402 case EOpConstructUVec3:
403 case EOpConstructUVec4:
404 case EOpConstructUInt:
405 case EOpConstructBVec2:
406 case EOpConstructBVec3:
407 case EOpConstructBVec4:
408 case EOpConstructBool:
409 case EOpConstructStruct:
410 return true;
411 default:
412 return false;
413 }
414}
415
416//
417// Make sure the type of a unary operator is appropriate for its
418// combination of operation and operand type.
419//
Olli Etuahof6c694b2015-03-26 14:50:53 +0200420void TIntermUnary::promote(const TType *funcReturnType)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400421{
422 switch (mOp)
423 {
Olli Etuahodca3e792015-03-26 13:24:04 +0200424 case EOpFloatBitsToInt:
425 case EOpFloatBitsToUint:
Olli Etuahoe8d2c072015-01-08 16:33:54 +0200426 case EOpIntBitsToFloat:
427 case EOpUintBitsToFloat:
Olli Etuahodca3e792015-03-26 13:24:04 +0200428 case EOpPackSnorm2x16:
429 case EOpPackUnorm2x16:
430 case EOpPackHalf2x16:
Olli Etuaho7700ff62015-01-15 12:16:29 +0200431 case EOpUnpackSnorm2x16:
432 case EOpUnpackUnorm2x16:
Olli Etuahodca3e792015-03-26 13:24:04 +0200433 mType.setPrecision(EbpHigh);
Arun Patole6b19d762015-02-19 09:40:39 +0530434 break;
Olli Etuahodca3e792015-03-26 13:24:04 +0200435 case EOpUnpackHalf2x16:
436 mType.setPrecision(EbpMedium);
437 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400438 default:
Olli Etuahodca3e792015-03-26 13:24:04 +0200439 setType(mOperand->getType());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400440 }
441
Olli Etuahof6c694b2015-03-26 14:50:53 +0200442 if (funcReturnType != nullptr)
443 {
444 if (funcReturnType->getBasicType() == EbtBool)
445 {
446 // Bool types should not have precision.
447 setType(*funcReturnType);
448 }
449 else
450 {
451 // Precision of the node has been set based on the operand.
452 setTypePreservePrecision(*funcReturnType);
453 }
454 }
455
Jamie Madillb1a85f42014-08-19 15:23:24 -0400456 mType.setQualifier(EvqTemporary);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400457}
458
459//
460// Establishes the type of the resultant operation, as well as
461// makes the operator the correct one for the operands.
462//
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200463// For lots of operations it should already be established that the operand
464// combination is valid, but returns false if operator can't work on operands.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400465//
466bool TIntermBinary::promote(TInfoSink &infoSink)
467{
Olli Etuahoe79904c2015-03-18 16:56:42 +0200468 ASSERT(mLeft->isArray() == mRight->isArray());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400469
Jamie Madillb1a85f42014-08-19 15:23:24 -0400470 //
471 // Base assumption: just make the type the same as the left
472 // operand. Then only deviations from this need be coded.
473 //
474 setType(mLeft->getType());
475
476 // The result gets promoted to the highest precision.
477 TPrecision higherPrecision = GetHigherPrecision(
478 mLeft->getPrecision(), mRight->getPrecision());
479 getTypePointer()->setPrecision(higherPrecision);
480
481 // Binary operations results in temporary variables unless both
482 // operands are const.
483 if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst)
484 {
485 getTypePointer()->setQualifier(EvqTemporary);
486 }
487
488 const int nominalSize =
489 std::max(mLeft->getNominalSize(), mRight->getNominalSize());
490
491 //
492 // All scalars or structs. Code after this test assumes this case is removed!
493 //
494 if (nominalSize == 1)
495 {
496 switch (mOp)
497 {
498 //
499 // Promote to conditional
500 //
501 case EOpEqual:
502 case EOpNotEqual:
503 case EOpLessThan:
504 case EOpGreaterThan:
505 case EOpLessThanEqual:
506 case EOpGreaterThanEqual:
507 setType(TType(EbtBool, EbpUndefined));
508 break;
509
510 //
511 // And and Or operate on conditionals
512 //
513 case EOpLogicalAnd:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200514 case EOpLogicalXor:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400515 case EOpLogicalOr:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200516 ASSERT(mLeft->getBasicType() == EbtBool && mRight->getBasicType() == EbtBool);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400517 setType(TType(EbtBool, EbpUndefined));
518 break;
519
520 default:
521 break;
522 }
523 return true;
524 }
525
526 // If we reach here, at least one of the operands is vector or matrix.
527 // The other operand could be a scalar, vector, or matrix.
528 // Can these two operands be combined?
529 //
530 TBasicType basicType = mLeft->getBasicType();
531 switch (mOp)
532 {
533 case EOpMul:
534 if (!mLeft->isMatrix() && mRight->isMatrix())
535 {
536 if (mLeft->isVector())
537 {
538 mOp = EOpVectorTimesMatrix;
539 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700540 static_cast<unsigned char>(mRight->getCols()), 1));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400541 }
542 else
543 {
544 mOp = EOpMatrixTimesScalar;
545 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700546 static_cast<unsigned char>(mRight->getCols()), static_cast<unsigned char>(mRight->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400547 }
548 }
549 else if (mLeft->isMatrix() && !mRight->isMatrix())
550 {
551 if (mRight->isVector())
552 {
553 mOp = EOpMatrixTimesVector;
554 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700555 static_cast<unsigned char>(mLeft->getRows()), 1));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400556 }
557 else
558 {
559 mOp = EOpMatrixTimesScalar;
560 }
561 }
562 else if (mLeft->isMatrix() && mRight->isMatrix())
563 {
564 mOp = EOpMatrixTimesMatrix;
565 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700566 static_cast<unsigned char>(mRight->getCols()), static_cast<unsigned char>(mLeft->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400567 }
568 else if (!mLeft->isMatrix() && !mRight->isMatrix())
569 {
570 if (mLeft->isVector() && mRight->isVector())
571 {
572 // leave as component product
573 }
574 else if (mLeft->isVector() || mRight->isVector())
575 {
576 mOp = EOpVectorTimesScalar;
577 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700578 static_cast<unsigned char>(nominalSize), 1));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400579 }
580 }
581 else
582 {
583 infoSink.info.message(EPrefixInternalError, getLine(),
584 "Missing elses");
585 return false;
586 }
587
588 if (!ValidateMultiplication(mOp, mLeft->getType(), mRight->getType()))
589 {
590 return false;
591 }
592 break;
593
594 case EOpMulAssign:
595 if (!mLeft->isMatrix() && mRight->isMatrix())
596 {
597 if (mLeft->isVector())
598 {
599 mOp = EOpVectorTimesMatrixAssign;
600 }
601 else
602 {
603 return false;
604 }
605 }
606 else if (mLeft->isMatrix() && !mRight->isMatrix())
607 {
608 if (mRight->isVector())
609 {
610 return false;
611 }
612 else
613 {
614 mOp = EOpMatrixTimesScalarAssign;
615 }
616 }
617 else if (mLeft->isMatrix() && mRight->isMatrix())
618 {
619 mOp = EOpMatrixTimesMatrixAssign;
620 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700621 static_cast<unsigned char>(mRight->getCols()), static_cast<unsigned char>(mLeft->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400622 }
623 else if (!mLeft->isMatrix() && !mRight->isMatrix())
624 {
625 if (mLeft->isVector() && mRight->isVector())
626 {
627 // leave as component product
628 }
629 else if (mLeft->isVector() || mRight->isVector())
630 {
631 if (!mLeft->isVector())
632 return false;
633 mOp = EOpVectorTimesScalarAssign;
634 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700635 static_cast<unsigned char>(mLeft->getNominalSize()), 1));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400636 }
637 }
638 else
639 {
640 infoSink.info.message(EPrefixInternalError, getLine(),
641 "Missing elses");
642 return false;
643 }
644
645 if (!ValidateMultiplication(mOp, mLeft->getType(), mRight->getType()))
646 {
647 return false;
648 }
649 break;
650
651 case EOpAssign:
652 case EOpInitialize:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200653 // No more additional checks are needed.
654 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
655 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
656 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400657 case EOpAdd:
658 case EOpSub:
659 case EOpDiv:
Olli Etuahoff805cc2015-02-13 10:59:34 +0200660 case EOpIMod:
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200661 case EOpBitShiftLeft:
662 case EOpBitShiftRight:
663 case EOpBitwiseAnd:
664 case EOpBitwiseXor:
665 case EOpBitwiseOr:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400666 case EOpAddAssign:
667 case EOpSubAssign:
668 case EOpDivAssign:
Olli Etuahoff805cc2015-02-13 10:59:34 +0200669 case EOpIModAssign:
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200670 case EOpBitShiftLeftAssign:
671 case EOpBitShiftRightAssign:
672 case EOpBitwiseAndAssign:
673 case EOpBitwiseXorAssign:
674 case EOpBitwiseOrAssign:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400675 if ((mLeft->isMatrix() && mRight->isVector()) ||
676 (mLeft->isVector() && mRight->isMatrix()))
677 {
678 return false;
679 }
680
681 // Are the sizes compatible?
682 if (mLeft->getNominalSize() != mRight->getNominalSize() ||
683 mLeft->getSecondarySize() != mRight->getSecondarySize())
684 {
Olli Etuaho6c850472014-12-02 16:23:17 +0200685 // If the nominal sizes of operands do not match:
686 // One of them must be a scalar.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400687 if (!mLeft->isScalar() && !mRight->isScalar())
688 return false;
689
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200690 // In the case of compound assignment other than multiply-assign,
691 // the right side needs to be a scalar. Otherwise a vector/matrix
692 // would be assigned to a scalar. A scalar can't be shifted by a
693 // vector either.
Olli Etuaho6c850472014-12-02 16:23:17 +0200694 if (!mRight->isScalar() &&
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200695 (isAssignment() ||
696 mOp == EOpBitShiftLeft ||
697 mOp == EOpBitShiftRight))
Olli Etuaho6c850472014-12-02 16:23:17 +0200698 return false;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400699 }
700
701 {
702 const int secondarySize = std::max(
703 mLeft->getSecondarySize(), mRight->getSecondarySize());
704 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700705 static_cast<unsigned char>(nominalSize), static_cast<unsigned char>(secondarySize)));
Olli Etuahoe79904c2015-03-18 16:56:42 +0200706 if (mLeft->isArray())
707 {
708 ASSERT(mLeft->getArraySize() == mRight->getArraySize());
709 mType.setArraySize(mLeft->getArraySize());
710 }
Jamie Madillb1a85f42014-08-19 15:23:24 -0400711 }
712 break;
713
714 case EOpEqual:
715 case EOpNotEqual:
716 case EOpLessThan:
717 case EOpGreaterThan:
718 case EOpLessThanEqual:
719 case EOpGreaterThanEqual:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200720 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
721 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400722 setType(TType(EbtBool, EbpUndefined));
723 break;
724
725 default:
726 return false;
727 }
728 return true;
729}
730
731//
732// The fold functions see if an operation on a constant can be done in place,
733// without generating run-time code.
734//
Jamie Madillaebd0022015-06-04 19:43:44 +0000735// Returns the node to keep using, which may or may not be the node passed in.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400736//
Jamie Madillaebd0022015-06-04 19:43:44 +0000737TIntermTyped *TIntermConstantUnion::fold(
738 TOperator op, TIntermConstantUnion *rightNode, TInfoSink &infoSink)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400739{
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400740 TConstantUnion *unionArray = getUnionArrayPointer();
Jamie Madillb1a85f42014-08-19 15:23:24 -0400741
742 if (!unionArray)
Arun Patolefddc2112015-04-22 13:28:10 +0530743 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400744
745 size_t objectSize = getType().getObjectSize();
746
Jamie Madillaebd0022015-06-04 19:43:44 +0000747 if (rightNode)
748 {
749 // binary operations
750 TConstantUnion *rightUnionArray = rightNode->getUnionArrayPointer();
751 TType returnType = getType();
752
753 if (!rightUnionArray)
754 return nullptr;
755
756 // for a case like float f = vec4(2, 3, 4, 5) + 1.2;
757 if (rightNode->getType().getObjectSize() == 1 && objectSize > 1)
758 {
759 rightUnionArray = Vectorize(*rightNode->getUnionArrayPointer(), objectSize);
760 returnType = getType();
761 }
762 else if (rightNode->getType().getObjectSize() > 1 && objectSize == 1)
763 {
764 // for a case like float f = 1.2 + vec4(2, 3, 4, 5);
765 unionArray = Vectorize(*getUnionArrayPointer(), rightNode->getType().getObjectSize());
766 returnType = rightNode->getType();
767 objectSize = rightNode->getType().getObjectSize();
768 }
769
770 TConstantUnion *tempConstArray = nullptr;
771 TIntermConstantUnion *tempNode;
772
773 bool boolNodeFlag = false;
774 switch(op)
775 {
776 case EOpAdd:
777 tempConstArray = new TConstantUnion[objectSize];
778 for (size_t i = 0; i < objectSize; i++)
779 tempConstArray[i] = unionArray[i] + rightUnionArray[i];
780 break;
781 case EOpSub:
782 tempConstArray = new TConstantUnion[objectSize];
783 for (size_t i = 0; i < objectSize; i++)
784 tempConstArray[i] = unionArray[i] - rightUnionArray[i];
785 break;
786
787 case EOpMul:
788 case EOpVectorTimesScalar:
789 case EOpMatrixTimesScalar:
790 tempConstArray = new TConstantUnion[objectSize];
791 for (size_t i = 0; i < objectSize; i++)
792 tempConstArray[i] = unionArray[i] * rightUnionArray[i];
793 break;
794
795 case EOpMatrixTimesMatrix:
796 {
797 if (getType().getBasicType() != EbtFloat ||
798 rightNode->getBasicType() != EbtFloat)
799 {
800 infoSink.info.message(
801 EPrefixInternalError, getLine(),
802 "Constant Folding cannot be done for matrix multiply");
803 return nullptr;
804 }
805
806 const int leftCols = getCols();
807 const int leftRows = getRows();
808 const int rightCols = rightNode->getType().getCols();
809 const int rightRows = rightNode->getType().getRows();
810 const int resultCols = rightCols;
811 const int resultRows = leftRows;
812
813 tempConstArray = new TConstantUnion[resultCols * resultRows];
814 for (int row = 0; row < resultRows; row++)
815 {
816 for (int column = 0; column < resultCols; column++)
817 {
818 tempConstArray[resultRows * column + row].setFConst(0.0f);
819 for (int i = 0; i < leftCols; i++)
820 {
821 tempConstArray[resultRows * column + row].setFConst(
822 tempConstArray[resultRows * column + row].getFConst() +
823 unionArray[i * leftRows + row].getFConst() *
824 rightUnionArray[column * rightRows + i].getFConst());
825 }
826 }
827 }
828
829 // update return type for matrix product
830 returnType.setPrimarySize(static_cast<unsigned char>(resultCols));
831 returnType.setSecondarySize(static_cast<unsigned char>(resultRows));
832 }
833 break;
834
835 case EOpDiv:
836 case EOpIMod:
837 {
838 tempConstArray = new TConstantUnion[objectSize];
839 for (size_t i = 0; i < objectSize; i++)
840 {
841 switch (getType().getBasicType())
842 {
843 case EbtFloat:
844 if (rightUnionArray[i] == 0.0f)
845 {
846 infoSink.info.message(
847 EPrefixWarning, getLine(),
848 "Divide by zero error during constant folding");
849 tempConstArray[i].setFConst(
850 unionArray[i].getFConst() < 0 ? -FLT_MAX : FLT_MAX);
851 }
852 else
853 {
854 ASSERT(op == EOpDiv);
855 tempConstArray[i].setFConst(
856 unionArray[i].getFConst() /
857 rightUnionArray[i].getFConst());
858 }
859 break;
860
861 case EbtInt:
862 if (rightUnionArray[i] == 0)
863 {
864 infoSink.info.message(
865 EPrefixWarning, getLine(),
866 "Divide by zero error during constant folding");
867 tempConstArray[i].setIConst(INT_MAX);
868 }
869 else
870 {
871 if (op == EOpDiv)
872 {
873 tempConstArray[i].setIConst(
874 unionArray[i].getIConst() /
875 rightUnionArray[i].getIConst());
876 }
877 else
878 {
879 ASSERT(op == EOpIMod);
880 tempConstArray[i].setIConst(
881 unionArray[i].getIConst() %
882 rightUnionArray[i].getIConst());
883 }
884 }
885 break;
886
887 case EbtUInt:
888 if (rightUnionArray[i] == 0)
889 {
890 infoSink.info.message(
891 EPrefixWarning, getLine(),
892 "Divide by zero error during constant folding");
893 tempConstArray[i].setUConst(UINT_MAX);
894 }
895 else
896 {
897 if (op == EOpDiv)
898 {
899 tempConstArray[i].setUConst(
900 unionArray[i].getUConst() /
901 rightUnionArray[i].getUConst());
902 }
903 else
904 {
905 ASSERT(op == EOpIMod);
906 tempConstArray[i].setUConst(
907 unionArray[i].getUConst() %
908 rightUnionArray[i].getUConst());
909 }
910 }
911 break;
912
913 default:
914 infoSink.info.message(
915 EPrefixInternalError, getLine(),
916 "Constant folding cannot be done for \"/\"");
917 return nullptr;
918 }
919 }
920 }
921 break;
922
923 case EOpMatrixTimesVector:
924 {
925 if (rightNode->getBasicType() != EbtFloat)
926 {
927 infoSink.info.message(
928 EPrefixInternalError, getLine(),
929 "Constant Folding cannot be done for matrix times vector");
930 return nullptr;
931 }
932
933 const int matrixCols = getCols();
934 const int matrixRows = getRows();
935
936 tempConstArray = new TConstantUnion[matrixRows];
937
938 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
939 {
940 tempConstArray[matrixRow].setFConst(0.0f);
941 for (int col = 0; col < matrixCols; col++)
942 {
943 tempConstArray[matrixRow].setFConst(
944 tempConstArray[matrixRow].getFConst() +
945 unionArray[col * matrixRows + matrixRow].getFConst() *
946 rightUnionArray[col].getFConst());
947 }
948 }
949
950 returnType = rightNode->getType();
951 returnType.setPrimarySize(static_cast<unsigned char>(matrixRows));
952
953 tempNode = new TIntermConstantUnion(tempConstArray, returnType);
954 tempNode->setLine(getLine());
955
956 return tempNode;
957 }
958
959 case EOpVectorTimesMatrix:
960 {
961 if (getType().getBasicType() != EbtFloat)
962 {
963 infoSink.info.message(
964 EPrefixInternalError, getLine(),
965 "Constant Folding cannot be done for vector times matrix");
966 return nullptr;
967 }
968
969 const int matrixCols = rightNode->getType().getCols();
970 const int matrixRows = rightNode->getType().getRows();
971
972 tempConstArray = new TConstantUnion[matrixCols];
973
974 for (int matrixCol = 0; matrixCol < matrixCols; matrixCol++)
975 {
976 tempConstArray[matrixCol].setFConst(0.0f);
977 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
978 {
979 tempConstArray[matrixCol].setFConst(
980 tempConstArray[matrixCol].getFConst() +
981 unionArray[matrixRow].getFConst() *
982 rightUnionArray[matrixCol * matrixRows + matrixRow].getFConst());
983 }
984 }
985
986 returnType.setPrimarySize(static_cast<unsigned char>(matrixCols));
987 }
988 break;
989
990 case EOpLogicalAnd:
991 // this code is written for possible future use,
992 // will not get executed currently
993 {
994 tempConstArray = new TConstantUnion[objectSize];
995 for (size_t i = 0; i < objectSize; i++)
996 {
997 tempConstArray[i] = unionArray[i] && rightUnionArray[i];
998 }
999 }
1000 break;
1001
1002 case EOpLogicalOr:
1003 // this code is written for possible future use,
1004 // will not get executed currently
1005 {
1006 tempConstArray = new TConstantUnion[objectSize];
1007 for (size_t i = 0; i < objectSize; i++)
1008 {
1009 tempConstArray[i] = unionArray[i] || rightUnionArray[i];
1010 }
1011 }
1012 break;
1013
1014 case EOpLogicalXor:
1015 {
1016 tempConstArray = new TConstantUnion[objectSize];
1017 for (size_t i = 0; i < objectSize; i++)
1018 {
1019 switch (getType().getBasicType())
1020 {
1021 case EbtBool:
1022 tempConstArray[i].setBConst(
1023 unionArray[i] == rightUnionArray[i] ? false : true);
1024 break;
1025 default:
1026 UNREACHABLE();
1027 break;
1028 }
1029 }
1030 }
1031 break;
1032
1033 case EOpBitwiseAnd:
1034 tempConstArray = new TConstantUnion[objectSize];
1035 for (size_t i = 0; i < objectSize; i++)
1036 tempConstArray[i] = unionArray[i] & rightUnionArray[i];
1037 break;
1038 case EOpBitwiseXor:
1039 tempConstArray = new TConstantUnion[objectSize];
1040 for (size_t i = 0; i < objectSize; i++)
1041 tempConstArray[i] = unionArray[i] ^ rightUnionArray[i];
1042 break;
1043 case EOpBitwiseOr:
1044 tempConstArray = new TConstantUnion[objectSize];
1045 for (size_t i = 0; i < objectSize; i++)
1046 tempConstArray[i] = unionArray[i] | rightUnionArray[i];
1047 break;
1048 case EOpBitShiftLeft:
1049 tempConstArray = new TConstantUnion[objectSize];
1050 for (size_t i = 0; i < objectSize; i++)
1051 tempConstArray[i] = unionArray[i] << rightUnionArray[i];
1052 break;
1053 case EOpBitShiftRight:
1054 tempConstArray = new TConstantUnion[objectSize];
1055 for (size_t i = 0; i < objectSize; i++)
1056 tempConstArray[i] = unionArray[i] >> rightUnionArray[i];
1057 break;
1058
1059 case EOpLessThan:
1060 ASSERT(objectSize == 1);
1061 tempConstArray = new TConstantUnion[1];
1062 tempConstArray->setBConst(*unionArray < *rightUnionArray);
1063 returnType = TType(EbtBool, EbpUndefined, EvqConst);
1064 break;
1065
1066 case EOpGreaterThan:
1067 ASSERT(objectSize == 1);
1068 tempConstArray = new TConstantUnion[1];
1069 tempConstArray->setBConst(*unionArray > *rightUnionArray);
1070 returnType = TType(EbtBool, EbpUndefined, EvqConst);
1071 break;
1072
1073 case EOpLessThanEqual:
1074 {
1075 ASSERT(objectSize == 1);
1076 TConstantUnion constant;
1077 constant.setBConst(*unionArray > *rightUnionArray);
1078 tempConstArray = new TConstantUnion[1];
1079 tempConstArray->setBConst(!constant.getBConst());
1080 returnType = TType(EbtBool, EbpUndefined, EvqConst);
1081 break;
1082 }
1083
1084 case EOpGreaterThanEqual:
1085 {
1086 ASSERT(objectSize == 1);
1087 TConstantUnion constant;
1088 constant.setBConst(*unionArray < *rightUnionArray);
1089 tempConstArray = new TConstantUnion[1];
1090 tempConstArray->setBConst(!constant.getBConst());
1091 returnType = TType(EbtBool, EbpUndefined, EvqConst);
1092 break;
1093 }
1094
1095 case EOpEqual:
1096 if (getType().getBasicType() == EbtStruct)
1097 {
1098 if (!CompareStructure(rightNode->getType(),
1099 rightNode->getUnionArrayPointer(),
1100 unionArray))
1101 {
1102 boolNodeFlag = true;
1103 }
1104 }
1105 else
1106 {
1107 for (size_t i = 0; i < objectSize; i++)
1108 {
1109 if (unionArray[i] != rightUnionArray[i])
1110 {
1111 boolNodeFlag = true;
1112 break; // break out of for loop
1113 }
1114 }
1115 }
1116
1117 tempConstArray = new TConstantUnion[1];
1118 if (!boolNodeFlag)
1119 {
1120 tempConstArray->setBConst(true);
1121 }
1122 else
1123 {
1124 tempConstArray->setBConst(false);
1125 }
1126
1127 tempNode = new TIntermConstantUnion(
1128 tempConstArray, TType(EbtBool, EbpUndefined, EvqConst));
1129 tempNode->setLine(getLine());
1130
1131 return tempNode;
1132
1133 case EOpNotEqual:
1134 if (getType().getBasicType() == EbtStruct)
1135 {
1136 if (CompareStructure(rightNode->getType(),
1137 rightNode->getUnionArrayPointer(),
1138 unionArray))
1139 {
1140 boolNodeFlag = true;
1141 }
1142 }
1143 else
1144 {
1145 for (size_t i = 0; i < objectSize; i++)
1146 {
1147 if (unionArray[i] == rightUnionArray[i])
1148 {
1149 boolNodeFlag = true;
1150 break; // break out of for loop
1151 }
1152 }
1153 }
1154
1155 tempConstArray = new TConstantUnion[1];
1156 if (!boolNodeFlag)
1157 {
1158 tempConstArray->setBConst(true);
1159 }
1160 else
1161 {
1162 tempConstArray->setBConst(false);
1163 }
1164
1165 tempNode = new TIntermConstantUnion(
1166 tempConstArray, TType(EbtBool, EbpUndefined, EvqConst));
1167 tempNode->setLine(getLine());
1168
1169 return tempNode;
1170
1171 default:
1172 infoSink.info.message(
1173 EPrefixInternalError, getLine(),
1174 "Invalid operator for constant folding");
1175 return nullptr;
1176 }
1177 tempNode = new TIntermConstantUnion(tempConstArray, returnType);
1178 tempNode->setLine(getLine());
1179
1180 return tempNode;
1181 }
Jamie Madillb3da45c2015-06-04 19:38:22 +00001182 else if (op == EOpAny || op == EOpAll)
Arun Patole9d0b1f92015-05-20 14:27:17 +05301183 {
1184 // Do operations where the return type is different from the operand type.
1185
Jamie Madillb3da45c2015-06-04 19:38:22 +00001186 TType returnType(EbtBool, EbpUndefined, EvqConst);
Arun Patole9d0b1f92015-05-20 14:27:17 +05301187 TConstantUnion *tempConstArray = nullptr;
Jamie Madillb3da45c2015-06-04 19:38:22 +00001188 if (op == EOpAny)
Arun Patole9d0b1f92015-05-20 14:27:17 +05301189 {
1190 if (getType().getBasicType() == EbtBool)
1191 {
1192 tempConstArray = new TConstantUnion();
1193 tempConstArray->setBConst(false);
1194 for (size_t i = 0; i < objectSize; i++)
1195 {
1196 if (unionArray[i].getBConst())
1197 {
1198 tempConstArray->setBConst(true);
1199 break;
1200 }
1201 }
1202 }
1203 else
1204 {
Jamie Madillb3da45c2015-06-04 19:38:22 +00001205 infoSink.info.message(
1206 EPrefixInternalError, getLine(),
1207 "Unary operation not folded into constant");
Arun Patole9d0b1f92015-05-20 14:27:17 +05301208 return nullptr;
1209 }
Jamie Madillb3da45c2015-06-04 19:38:22 +00001210 }
1211 else if (op == EOpAll)
1212 {
Arun Patole9d0b1f92015-05-20 14:27:17 +05301213 if (getType().getBasicType() == EbtBool)
1214 {
1215 tempConstArray = new TConstantUnion();
1216 tempConstArray->setBConst(true);
1217 for (size_t i = 0; i < objectSize; i++)
1218 {
1219 if (!unionArray[i].getBConst())
1220 {
1221 tempConstArray->setBConst(false);
1222 break;
1223 }
1224 }
1225 }
1226 else
1227 {
Jamie Madillb3da45c2015-06-04 19:38:22 +00001228 infoSink.info.message(
1229 EPrefixInternalError, getLine(),
1230 "Unary operation not folded into constant");
Arun Patole9d0b1f92015-05-20 14:27:17 +05301231 return nullptr;
1232 }
1233 }
1234 TIntermConstantUnion *tempNode = new TIntermConstantUnion(tempConstArray, returnType);
1235 tempNode->setLine(getLine());
1236 return tempNode;
1237 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04001238 else
1239 {
1240 //
Arun Patole9d0b1f92015-05-20 14:27:17 +05301241 // Do unary operations where the return type is the same as operand type.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001242 //
1243 TIntermConstantUnion *newNode = 0;
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001244 TConstantUnion* tempConstArray = new TConstantUnion[objectSize];
Jamie Madillb1a85f42014-08-19 15:23:24 -04001245 for (size_t i = 0; i < objectSize; i++)
1246 {
1247 switch(op)
1248 {
1249 case EOpNegative:
1250 switch (getType().getBasicType())
1251 {
1252 case EbtFloat:
1253 tempConstArray[i].setFConst(-unionArray[i].getFConst());
1254 break;
1255 case EbtInt:
1256 tempConstArray[i].setIConst(-unionArray[i].getIConst());
1257 break;
1258 case EbtUInt:
1259 tempConstArray[i].setUConst(static_cast<unsigned int>(
1260 -static_cast<int>(unionArray[i].getUConst())));
1261 break;
1262 default:
1263 infoSink.info.message(
1264 EPrefixInternalError, getLine(),
1265 "Unary operation not folded into constant");
Arun Patolefddc2112015-04-22 13:28:10 +05301266 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001267 }
1268 break;
1269
Zhenyao Mode1e00e2014-10-09 16:55:32 -07001270 case EOpPositive:
1271 switch (getType().getBasicType())
1272 {
1273 case EbtFloat:
1274 tempConstArray[i].setFConst(unionArray[i].getFConst());
1275 break;
1276 case EbtInt:
1277 tempConstArray[i].setIConst(unionArray[i].getIConst());
1278 break;
1279 case EbtUInt:
1280 tempConstArray[i].setUConst(static_cast<unsigned int>(
1281 static_cast<int>(unionArray[i].getUConst())));
1282 break;
1283 default:
1284 infoSink.info.message(
1285 EPrefixInternalError, getLine(),
1286 "Unary operation not folded into constant");
Arun Patolefddc2112015-04-22 13:28:10 +05301287 return nullptr;
Zhenyao Mode1e00e2014-10-09 16:55:32 -07001288 }
1289 break;
1290
Jamie Madillb1a85f42014-08-19 15:23:24 -04001291 case EOpLogicalNot:
1292 // this code is written for possible future use,
1293 // will not get executed currently
1294 switch (getType().getBasicType())
1295 {
1296 case EbtBool:
1297 tempConstArray[i].setBConst(!unionArray[i].getBConst());
1298 break;
1299 default:
1300 infoSink.info.message(
1301 EPrefixInternalError, getLine(),
1302 "Unary operation not folded into constant");
Arun Patolefddc2112015-04-22 13:28:10 +05301303 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001304 }
1305 break;
1306
Olli Etuaho31b5fc62015-01-16 12:13:36 +02001307 case EOpBitwiseNot:
1308 switch (getType().getBasicType())
1309 {
1310 case EbtInt:
1311 tempConstArray[i].setIConst(~unionArray[i].getIConst());
1312 break;
1313 case EbtUInt:
1314 tempConstArray[i].setUConst(~unionArray[i].getUConst());
1315 break;
1316 default:
1317 infoSink.info.message(
1318 EPrefixInternalError, getLine(),
1319 "Unary operation not folded into constant");
Arun Patolefddc2112015-04-22 13:28:10 +05301320 return nullptr;
Olli Etuaho31b5fc62015-01-16 12:13:36 +02001321 }
1322 break;
1323
Arun Patole9dea48f2015-04-02 11:45:09 +05301324 case EOpRadians:
1325 if (getType().getBasicType() == EbtFloat)
1326 {
1327 tempConstArray[i].setFConst(kDegreesToRadiansMultiplier * unionArray[i].getFConst());
1328 break;
1329 }
1330 infoSink.info.message(
1331 EPrefixInternalError, getLine(),
1332 "Unary operation not folded into constant");
1333 return nullptr;
1334
1335 case EOpDegrees:
1336 if (getType().getBasicType() == EbtFloat)
1337 {
1338 tempConstArray[i].setFConst(kRadiansToDegreesMultiplier * unionArray[i].getFConst());
1339 break;
1340 }
1341 infoSink.info.message(
1342 EPrefixInternalError, getLine(),
1343 "Unary operation not folded into constant");
1344 return nullptr;
1345
1346 case EOpSin:
1347 if (!foldFloatTypeUnary(unionArray[i], &sinf, infoSink, &tempConstArray[i]))
1348 return nullptr;
1349 break;
1350
1351 case EOpCos:
1352 if (!foldFloatTypeUnary(unionArray[i], &cosf, infoSink, &tempConstArray[i]))
1353 return nullptr;
1354 break;
1355
1356 case EOpTan:
1357 if (!foldFloatTypeUnary(unionArray[i], &tanf, infoSink, &tempConstArray[i]))
1358 return nullptr;
1359 break;
1360
1361 case EOpAsin:
1362 // For asin(x), results are undefined if |x| > 1, we are choosing to set result to 0.
1363 if (getType().getBasicType() == EbtFloat && fabsf(unionArray[i].getFConst()) > 1.0f)
Arun Patole081c3f22015-05-25 15:43:35 +05301364 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &tempConstArray[i]);
Arun Patole9dea48f2015-04-02 11:45:09 +05301365 else if (!foldFloatTypeUnary(unionArray[i], &asinf, infoSink, &tempConstArray[i]))
1366 return nullptr;
1367 break;
1368
1369 case EOpAcos:
1370 // For acos(x), results are undefined if |x| > 1, we are choosing to set result to 0.
1371 if (getType().getBasicType() == EbtFloat && fabsf(unionArray[i].getFConst()) > 1.0f)
Arun Patole081c3f22015-05-25 15:43:35 +05301372 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &tempConstArray[i]);
Arun Patole9dea48f2015-04-02 11:45:09 +05301373 else if (!foldFloatTypeUnary(unionArray[i], &acosf, infoSink, &tempConstArray[i]))
1374 return nullptr;
1375 break;
1376
1377 case EOpAtan:
1378 if (!foldFloatTypeUnary(unionArray[i], &atanf, infoSink, &tempConstArray[i]))
1379 return nullptr;
1380 break;
1381
1382 case EOpSinh:
1383 if (!foldFloatTypeUnary(unionArray[i], &sinhf, infoSink, &tempConstArray[i]))
1384 return nullptr;
1385 break;
1386
1387 case EOpCosh:
1388 if (!foldFloatTypeUnary(unionArray[i], &coshf, infoSink, &tempConstArray[i]))
1389 return nullptr;
1390 break;
1391
1392 case EOpTanh:
1393 if (!foldFloatTypeUnary(unionArray[i], &tanhf, infoSink, &tempConstArray[i]))
1394 return nullptr;
1395 break;
1396
1397 case EOpAsinh:
1398 if (!foldFloatTypeUnary(unionArray[i], &asinhf, infoSink, &tempConstArray[i]))
1399 return nullptr;
1400 break;
1401
1402 case EOpAcosh:
1403 // For acosh(x), results are undefined if x < 1, we are choosing to set result to 0.
1404 if (getType().getBasicType() == EbtFloat && unionArray[i].getFConst() < 1.0f)
Arun Patole081c3f22015-05-25 15:43:35 +05301405 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &tempConstArray[i]);
Arun Patole9dea48f2015-04-02 11:45:09 +05301406 else if (!foldFloatTypeUnary(unionArray[i], &acoshf, infoSink, &tempConstArray[i]))
1407 return nullptr;
1408 break;
1409
1410 case EOpAtanh:
1411 // For atanh(x), results are undefined if |x| >= 1, we are choosing to set result to 0.
1412 if (getType().getBasicType() == EbtFloat && fabsf(unionArray[i].getFConst()) >= 1.0f)
Arun Patole081c3f22015-05-25 15:43:35 +05301413 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &tempConstArray[i]);
Arun Patole9dea48f2015-04-02 11:45:09 +05301414 else if (!foldFloatTypeUnary(unionArray[i], &atanhf, infoSink, &tempConstArray[i]))
1415 return nullptr;
1416 break;
1417
Arun Patole97dc22e2015-04-06 17:35:38 +05301418 case EOpAbs:
1419 switch (getType().getBasicType())
1420 {
1421 case EbtFloat:
1422 tempConstArray[i].setFConst(fabsf(unionArray[i].getFConst()));
1423 break;
1424 case EbtInt:
1425 tempConstArray[i].setIConst(abs(unionArray[i].getIConst()));
1426 break;
1427 default:
1428 infoSink.info.message(
1429 EPrefixInternalError, getLine(),
1430 "Unary operation not folded into constant");
1431 return nullptr;
1432 }
1433 break;
1434
1435 case EOpSign:
1436 switch (getType().getBasicType())
1437 {
1438 case EbtFloat:
1439 {
1440 float fConst = unionArray[i].getFConst();
1441 float fResult = 0.0f;
1442 if (fConst > 0.0f)
1443 fResult = 1.0f;
1444 else if (fConst < 0.0f)
1445 fResult = -1.0f;
1446 tempConstArray[i].setFConst(fResult);
1447 }
1448 break;
1449 case EbtInt:
1450 {
1451 int iConst = unionArray[i].getIConst();
1452 int iResult = 0;
1453 if (iConst > 0)
1454 iResult = 1;
1455 else if (iConst < 0)
1456 iResult = -1;
1457 tempConstArray[i].setIConst(iResult);
1458 }
1459 break;
1460 default:
1461 infoSink.info.message(
1462 EPrefixInternalError, getLine(),
1463 "Unary operation not folded into constant");
1464 return nullptr;
1465 }
1466 break;
1467
1468 case EOpFloor:
1469 if (!foldFloatTypeUnary(unionArray[i], &floorf, infoSink, &tempConstArray[i]))
1470 return nullptr;
1471 break;
1472
1473 case EOpTrunc:
1474 if (!foldFloatTypeUnary(unionArray[i], &truncf, infoSink, &tempConstArray[i]))
1475 return nullptr;
1476 break;
1477
1478 case EOpRound:
1479 if (!foldFloatTypeUnary(unionArray[i], &roundf, infoSink, &tempConstArray[i]))
1480 return nullptr;
1481 break;
1482
1483 case EOpRoundEven:
1484 if (getType().getBasicType() == EbtFloat)
1485 {
1486 float x = unionArray[i].getFConst();
1487 float result;
1488 float fractPart = modff(x, &result);
1489 if (fabsf(fractPart) == 0.5f)
1490 result = 2.0f * roundf(x / 2.0f);
1491 else
1492 result = roundf(x);
1493 tempConstArray[i].setFConst(result);
1494 break;
1495 }
1496 infoSink.info.message(
1497 EPrefixInternalError, getLine(),
1498 "Unary operation not folded into constant");
1499 return nullptr;
1500
1501 case EOpCeil:
1502 if (!foldFloatTypeUnary(unionArray[i], &ceilf, infoSink, &tempConstArray[i]))
1503 return nullptr;
1504 break;
1505
1506 case EOpFract:
1507 if (getType().getBasicType() == EbtFloat)
1508 {
1509 float x = unionArray[i].getFConst();
1510 tempConstArray[i].setFConst(x - floorf(x));
1511 break;
1512 }
1513 infoSink.info.message(
1514 EPrefixInternalError, getLine(),
1515 "Unary operation not folded into constant");
1516 return nullptr;
1517
Arun Patole28eb65e2015-04-06 17:29:48 +05301518 case EOpExp:
1519 if (!foldFloatTypeUnary(unionArray[i], &expf, infoSink, &tempConstArray[i]))
1520 return nullptr;
1521 break;
1522
1523 case EOpLog:
1524 // For log(x), results are undefined if x <= 0, we are choosing to set result to 0.
1525 if (getType().getBasicType() == EbtFloat && unionArray[i].getFConst() <= 0.0f)
Arun Patole081c3f22015-05-25 15:43:35 +05301526 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &tempConstArray[i]);
Arun Patole28eb65e2015-04-06 17:29:48 +05301527 else if (!foldFloatTypeUnary(unionArray[i], &logf, infoSink, &tempConstArray[i]))
1528 return nullptr;
1529 break;
1530
1531 case EOpExp2:
1532 if (!foldFloatTypeUnary(unionArray[i], &exp2f, infoSink, &tempConstArray[i]))
1533 return nullptr;
1534 break;
1535
1536 case EOpLog2:
1537 // For log2(x), results are undefined if x <= 0, we are choosing to set result to 0.
1538 // And log2f is not available on some plarforms like old android, so just using log(x)/log(2) here.
1539 if (getType().getBasicType() == EbtFloat && unionArray[i].getFConst() <= 0.0f)
Arun Patole081c3f22015-05-25 15:43:35 +05301540 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &tempConstArray[i]);
Arun Patole28eb65e2015-04-06 17:29:48 +05301541 else if (!foldFloatTypeUnary(unionArray[i], &logf, infoSink, &tempConstArray[i]))
1542 return nullptr;
1543 else
1544 tempConstArray[i].setFConst(tempConstArray[i].getFConst() / logf(2.0f));
1545 break;
1546
1547 case EOpSqrt:
1548 // For sqrt(x), results are undefined if x < 0, we are choosing to set result to 0.
1549 if (getType().getBasicType() == EbtFloat && unionArray[i].getFConst() < 0.0f)
Arun Patole081c3f22015-05-25 15:43:35 +05301550 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &tempConstArray[i]);
Arun Patole28eb65e2015-04-06 17:29:48 +05301551 else if (!foldFloatTypeUnary(unionArray[i], &sqrtf, infoSink, &tempConstArray[i]))
1552 return nullptr;
1553 break;
1554
1555 case EOpInverseSqrt:
1556 // There is no stdlib built-in function equavalent for GLES built-in inversesqrt(),
1557 // so getting the square root first using builtin function sqrt() and then taking its inverse.
1558 // Also, for inversesqrt(x), results are undefined if x <= 0, we are choosing to set result to 0.
1559 if (getType().getBasicType() == EbtFloat && unionArray[i].getFConst() <= 0.0f)
Arun Patole081c3f22015-05-25 15:43:35 +05301560 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &tempConstArray[i]);
Arun Patole28eb65e2015-04-06 17:29:48 +05301561 else if (!foldFloatTypeUnary(unionArray[i], &sqrtf, infoSink, &tempConstArray[i]))
1562 return nullptr;
1563 else
1564 tempConstArray[i].setFConst(1.0f / tempConstArray[i].getFConst());
1565 break;
1566
Arun Patole9d0b1f92015-05-20 14:27:17 +05301567 case EOpVectorLogicalNot:
1568 if (getType().getBasicType() == EbtBool)
1569 {
1570 tempConstArray[i].setBConst(!unionArray[i].getBConst());
1571 break;
1572 }
1573 infoSink.info.message(
1574 EPrefixInternalError, getLine(),
1575 "Unary operation not folded into constant");
1576 return nullptr;
1577
Jamie Madillb1a85f42014-08-19 15:23:24 -04001578 default:
Arun Patolefddc2112015-04-22 13:28:10 +05301579 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001580 }
1581 }
1582 newNode = new TIntermConstantUnion(tempConstArray, getType());
1583 newNode->setLine(getLine());
1584 return newNode;
1585 }
1586}
1587
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001588bool TIntermConstantUnion::foldFloatTypeUnary(const TConstantUnion &parameter, FloatTypeUnaryFunc builtinFunc,
1589 TInfoSink &infoSink, TConstantUnion *result) const
Arun Patole9dea48f2015-04-02 11:45:09 +05301590{
1591 ASSERT(builtinFunc);
1592
1593 if (getType().getBasicType() == EbtFloat)
1594 {
1595 result->setFConst(builtinFunc(parameter.getFConst()));
1596 return true;
1597 }
1598
1599 infoSink.info.message(
1600 EPrefixInternalError, getLine(),
1601 "Unary operation not folded into constant");
1602 return false;
1603}
1604
Jamie Madillb1a85f42014-08-19 15:23:24 -04001605// static
Arun Patolebf790422015-05-18 17:53:04 +05301606TIntermTyped *TIntermConstantUnion::FoldAggregateBuiltIn(TOperator op, TIntermAggregate *aggregate, TInfoSink &infoSink)
Arun Patole274f0702015-05-05 13:33:30 +05301607{
1608 TIntermSequence *sequence = aggregate->getSequence();
1609 unsigned int paramsCount = sequence->size();
1610 std::vector<TConstantUnion *> unionArrays(paramsCount);
1611 std::vector<size_t> objectSizes(paramsCount);
1612 TType *maxSizeType = nullptr;
1613 TBasicType basicType = EbtVoid;
1614 TSourceLoc loc;
1615 for (unsigned int i = 0; i < paramsCount; i++)
1616 {
1617 TIntermConstantUnion *paramConstant = (*sequence)[i]->getAsConstantUnion();
1618 // Make sure that all params are constant before actual constant folding.
1619 if (!paramConstant)
1620 return nullptr;
1621
1622 if (i == 0)
1623 {
1624 basicType = paramConstant->getType().getBasicType();
1625 loc = paramConstant->getLine();
1626 }
1627 unionArrays[i] = paramConstant->getUnionArrayPointer();
1628 objectSizes[i] = paramConstant->getType().getObjectSize();
1629 if (maxSizeType == nullptr || (objectSizes[i] >= maxSizeType->getObjectSize()))
1630 maxSizeType = paramConstant->getTypePointer();
1631 }
1632
1633 size_t maxObjectSize = maxSizeType->getObjectSize();
1634 for (unsigned int i = 0; i < paramsCount; i++)
1635 if (objectSizes[i] != maxObjectSize)
1636 unionArrays[i] = Vectorize(*unionArrays[i], maxObjectSize);
1637
1638 TConstantUnion *tempConstArray = nullptr;
1639 TIntermConstantUnion *tempNode = nullptr;
1640 TType returnType = *maxSizeType;
1641 if (paramsCount == 2)
1642 {
1643 //
1644 // Binary built-in
1645 //
1646 switch (op)
1647 {
Arun Patolebf790422015-05-18 17:53:04 +05301648 case EOpAtan:
1649 {
1650 if (basicType == EbtFloat)
1651 {
1652 tempConstArray = new TConstantUnion[maxObjectSize];
1653 for (size_t i = 0; i < maxObjectSize; i++)
1654 {
1655 float y = unionArrays[0][i].getFConst();
1656 float x = unionArrays[1][i].getFConst();
1657 // Results are undefined if x and y are both 0.
1658 if (x == 0.0f && y == 0.0f)
1659 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &tempConstArray[i]);
1660 else
1661 tempConstArray[i].setFConst(atan2f(y, x));
1662 }
1663 }
1664 else
1665 UNREACHABLE();
1666 }
1667 break;
1668
1669 case EOpPow:
1670 {
1671 if (basicType == EbtFloat)
1672 {
1673 tempConstArray = new TConstantUnion[maxObjectSize];
1674 for (size_t i = 0; i < maxObjectSize; i++)
1675 {
1676 float x = unionArrays[0][i].getFConst();
1677 float y = unionArrays[1][i].getFConst();
1678 // Results are undefined if x < 0.
1679 // Results are undefined if x = 0 and y <= 0.
1680 if (x < 0.0f)
1681 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &tempConstArray[i]);
1682 else if (x == 0.0f && y <= 0.0f)
1683 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &tempConstArray[i]);
1684 else
1685 tempConstArray[i].setFConst(powf(x, y));
1686 }
1687 }
1688 else
1689 UNREACHABLE();
1690 }
1691 break;
1692
1693 case EOpMod:
1694 {
1695 if (basicType == EbtFloat)
1696 {
1697 tempConstArray = new TConstantUnion[maxObjectSize];
1698 for (size_t i = 0; i < maxObjectSize; i++)
1699 {
1700 float x = unionArrays[0][i].getFConst();
1701 float y = unionArrays[1][i].getFConst();
1702 tempConstArray[i].setFConst(x - y * floorf(x / y));
1703 }
1704 }
1705 else
1706 UNREACHABLE();
1707 }
1708 break;
1709
Arun Patole274f0702015-05-05 13:33:30 +05301710 case EOpMin:
1711 {
1712 tempConstArray = new TConstantUnion[maxObjectSize];
1713 for (size_t i = 0; i < maxObjectSize; i++)
1714 {
1715 switch (basicType)
1716 {
1717 case EbtFloat:
1718 tempConstArray[i].setFConst(std::min(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
1719 break;
1720 case EbtInt:
1721 tempConstArray[i].setIConst(std::min(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
1722 break;
1723 case EbtUInt:
1724 tempConstArray[i].setUConst(std::min(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
1725 break;
1726 default:
1727 UNREACHABLE();
1728 break;
1729 }
1730 }
1731 }
1732 break;
1733
1734 case EOpMax:
1735 {
1736 tempConstArray = new TConstantUnion[maxObjectSize];
1737 for (size_t i = 0; i < maxObjectSize; i++)
1738 {
1739 switch (basicType)
1740 {
1741 case EbtFloat:
1742 tempConstArray[i].setFConst(std::max(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
1743 break;
1744 case EbtInt:
1745 tempConstArray[i].setIConst(std::max(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
1746 break;
1747 case EbtUInt:
1748 tempConstArray[i].setUConst(std::max(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
1749 break;
1750 default:
1751 UNREACHABLE();
1752 break;
1753 }
1754 }
1755 }
1756 break;
1757
Arun Patolebf790422015-05-18 17:53:04 +05301758 case EOpStep:
1759 {
1760 if (basicType == EbtFloat)
1761 {
1762 tempConstArray = new TConstantUnion[maxObjectSize];
1763 for (size_t i = 0; i < maxObjectSize; i++)
1764 tempConstArray[i].setFConst(unionArrays[1][i].getFConst() < unionArrays[0][i].getFConst() ? 0.0f : 1.0f);
1765 }
1766 else
1767 UNREACHABLE();
1768 }
1769 break;
1770
Arun Patole9d0b1f92015-05-20 14:27:17 +05301771 case EOpLessThan:
1772 {
1773 tempConstArray = new TConstantUnion[maxObjectSize];
1774 for (size_t i = 0; i < maxObjectSize; i++)
1775 {
1776 switch (basicType)
1777 {
1778 case EbtFloat:
1779 tempConstArray[i].setBConst(unionArrays[0][i].getFConst() < unionArrays[1][i].getFConst());
1780 break;
1781 case EbtInt:
1782 tempConstArray[i].setBConst(unionArrays[0][i].getIConst() < unionArrays[1][i].getIConst());
1783 break;
1784 case EbtUInt:
1785 tempConstArray[i].setBConst(unionArrays[0][i].getUConst() < unionArrays[1][i].getUConst());
1786 break;
1787 default:
1788 UNREACHABLE();
1789 break;
1790 }
1791 }
1792 }
1793 break;
1794
1795 case EOpLessThanEqual:
1796 {
1797 tempConstArray = new TConstantUnion[maxObjectSize];
1798 for (size_t i = 0; i < maxObjectSize; i++)
1799 {
1800 switch (basicType)
1801 {
1802 case EbtFloat:
1803 tempConstArray[i].setBConst(unionArrays[0][i].getFConst() <= unionArrays[1][i].getFConst());
1804 break;
1805 case EbtInt:
1806 tempConstArray[i].setBConst(unionArrays[0][i].getIConst() <= unionArrays[1][i].getIConst());
1807 break;
1808 case EbtUInt:
1809 tempConstArray[i].setBConst(unionArrays[0][i].getUConst() <= unionArrays[1][i].getUConst());
1810 break;
1811 default:
1812 UNREACHABLE();
1813 break;
1814 }
1815 }
1816 }
1817 break;
1818
1819 case EOpGreaterThan:
1820 {
1821 tempConstArray = new TConstantUnion[maxObjectSize];
1822 for (size_t i = 0; i < maxObjectSize; i++)
1823 {
1824 switch (basicType)
1825 {
1826 case EbtFloat:
1827 tempConstArray[i].setBConst(unionArrays[0][i].getFConst() > unionArrays[1][i].getFConst());
1828 break;
1829 case EbtInt:
1830 tempConstArray[i].setBConst(unionArrays[0][i].getIConst() > unionArrays[1][i].getIConst());
1831 break;
1832 case EbtUInt:
1833 tempConstArray[i].setBConst(unionArrays[0][i].getUConst() > unionArrays[1][i].getUConst());
1834 break;
1835 default:
1836 UNREACHABLE();
1837 break;
1838 }
1839 }
1840 }
1841 break;
1842
1843 case EOpGreaterThanEqual:
1844 {
1845 tempConstArray = new TConstantUnion[maxObjectSize];
1846 for (size_t i = 0; i < maxObjectSize; i++)
1847 {
1848 switch (basicType)
1849 {
1850 case EbtFloat:
1851 tempConstArray[i].setBConst(unionArrays[0][i].getFConst() >= unionArrays[1][i].getFConst());
1852 break;
1853 case EbtInt:
1854 tempConstArray[i].setBConst(unionArrays[0][i].getIConst() >= unionArrays[1][i].getIConst());
1855 break;
1856 case EbtUInt:
1857 tempConstArray[i].setBConst(unionArrays[0][i].getUConst() >= unionArrays[1][i].getUConst());
1858 break;
1859 default:
1860 UNREACHABLE();
1861 break;
1862 }
1863 }
1864 }
1865 break;
1866
1867 case EOpVectorEqual:
1868 {
1869 tempConstArray = new TConstantUnion[maxObjectSize];
1870 for (size_t i = 0; i < maxObjectSize; i++)
1871 {
1872 switch (basicType)
1873 {
1874 case EbtFloat:
1875 tempConstArray[i].setBConst(unionArrays[0][i].getFConst() == unionArrays[1][i].getFConst());
1876 break;
1877 case EbtInt:
1878 tempConstArray[i].setBConst(unionArrays[0][i].getIConst() == unionArrays[1][i].getIConst());
1879 break;
1880 case EbtUInt:
1881 tempConstArray[i].setBConst(unionArrays[0][i].getUConst() == unionArrays[1][i].getUConst());
1882 break;
1883 case EbtBool:
1884 tempConstArray[i].setBConst(unionArrays[0][i].getBConst() == unionArrays[1][i].getBConst());
1885 break;
1886 default:
1887 UNREACHABLE();
1888 break;
1889 }
1890 }
1891 }
1892 break;
1893
1894 case EOpVectorNotEqual:
1895 {
1896 tempConstArray = new TConstantUnion[maxObjectSize];
1897 for (size_t i = 0; i < maxObjectSize; i++)
1898 {
1899 switch (basicType)
1900 {
1901 case EbtFloat:
1902 tempConstArray[i].setBConst(unionArrays[0][i].getFConst() != unionArrays[1][i].getFConst());
1903 break;
1904 case EbtInt:
1905 tempConstArray[i].setBConst(unionArrays[0][i].getIConst() != unionArrays[1][i].getIConst());
1906 break;
1907 case EbtUInt:
1908 tempConstArray[i].setBConst(unionArrays[0][i].getUConst() != unionArrays[1][i].getUConst());
1909 break;
1910 case EbtBool:
1911 tempConstArray[i].setBConst(unionArrays[0][i].getBConst() != unionArrays[1][i].getBConst());
1912 break;
1913 default:
1914 UNREACHABLE();
1915 break;
1916 }
1917 }
1918 }
1919 break;
1920
Arun Patole274f0702015-05-05 13:33:30 +05301921 default:
1922 UNREACHABLE();
1923 // TODO: Add constant folding support for other built-in operations that take 2 parameters and not handled above.
1924 return nullptr;
1925 }
1926 }
1927 else if (paramsCount == 3)
1928 {
1929 //
1930 // Ternary built-in
1931 //
1932 switch (op)
1933 {
1934 case EOpClamp:
1935 {
1936 tempConstArray = new TConstantUnion[maxObjectSize];
1937 for (size_t i = 0; i < maxObjectSize; i++)
1938 {
1939 switch (basicType)
1940 {
1941 case EbtFloat:
1942 {
1943 float x = unionArrays[0][i].getFConst();
1944 float min = unionArrays[1][i].getFConst();
1945 float max = unionArrays[2][i].getFConst();
1946 // Results are undefined if min > max.
1947 if (min > max)
Arun Patole081c3f22015-05-25 15:43:35 +05301948 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &tempConstArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05301949 else
1950 tempConstArray[i].setFConst(gl::clamp(x, min, max));
1951 }
1952 break;
1953 case EbtInt:
1954 {
1955 int x = unionArrays[0][i].getIConst();
1956 int min = unionArrays[1][i].getIConst();
1957 int max = unionArrays[2][i].getIConst();
1958 // Results are undefined if min > max.
1959 if (min > max)
Arun Patole081c3f22015-05-25 15:43:35 +05301960 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &tempConstArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05301961 else
1962 tempConstArray[i].setIConst(gl::clamp(x, min, max));
1963 }
1964 break;
1965 case EbtUInt:
1966 {
1967 unsigned int x = unionArrays[0][i].getUConst();
1968 unsigned int min = unionArrays[1][i].getUConst();
1969 unsigned int max = unionArrays[2][i].getUConst();
1970 // Results are undefined if min > max.
1971 if (min > max)
Arun Patole081c3f22015-05-25 15:43:35 +05301972 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &tempConstArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05301973 else
1974 tempConstArray[i].setUConst(gl::clamp(x, min, max));
1975 }
1976 break;
1977 default:
1978 UNREACHABLE();
1979 break;
1980 }
1981 }
1982 }
1983 break;
1984
Arun Patolebf790422015-05-18 17:53:04 +05301985 case EOpMix:
1986 {
1987 if (basicType == EbtFloat)
1988 {
1989 tempConstArray = new TConstantUnion[maxObjectSize];
1990 for (size_t i = 0; i < maxObjectSize; i++)
1991 {
1992 float x = unionArrays[0][i].getFConst();
1993 float y = unionArrays[1][i].getFConst();
1994 TBasicType type = (*sequence)[2]->getAsTyped()->getType().getBasicType();
1995 if (type == EbtFloat)
1996 {
1997 // Returns the linear blend of x and y, i.e., x * (1 - a) + y * a.
1998 float a = unionArrays[2][i].getFConst();
1999 tempConstArray[i].setFConst(x * (1.0f - a) + y * a);
2000 }
2001 else // 3rd parameter is EbtBool
2002 {
2003 ASSERT(type == EbtBool);
2004 // Selects which vector each returned component comes from.
2005 // For a component of a that is false, the corresponding component of x is returned.
2006 // For a component of a that is true, the corresponding component of y is returned.
2007 bool a = unionArrays[2][i].getBConst();
2008 tempConstArray[i].setFConst(a ? y : x);
2009 }
2010 }
2011 }
2012 else
2013 UNREACHABLE();
2014 }
2015 break;
2016
2017 case EOpSmoothStep:
2018 {
2019 if (basicType == EbtFloat)
2020 {
2021 tempConstArray = new TConstantUnion[maxObjectSize];
2022 for (size_t i = 0; i < maxObjectSize; i++)
2023 {
2024 float edge0 = unionArrays[0][i].getFConst();
2025 float edge1 = unionArrays[1][i].getFConst();
2026 float x = unionArrays[2][i].getFConst();
2027 // Results are undefined if edge0 >= edge1.
2028 if (edge0 >= edge1)
2029 {
2030 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &tempConstArray[i]);
2031 }
2032 else
2033 {
2034 // Returns 0.0 if x <= edge0 and 1.0 if x >= edge1 and performs smooth
2035 // Hermite interpolation between 0 and 1 when edge0 < x < edge1.
2036 float t = gl::clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f);
2037 tempConstArray[i].setFConst(t * t * (3.0f - 2.0f * t));
2038 }
2039 }
2040 }
2041 else
2042 UNREACHABLE();
2043 }
2044 break;
2045
Arun Patole274f0702015-05-05 13:33:30 +05302046 default:
2047 UNREACHABLE();
2048 // TODO: Add constant folding support for other built-in operations that take 3 parameters and not handled above.
2049 return nullptr;
2050 }
2051 }
2052
2053 if (tempConstArray)
2054 {
2055 tempNode = new TIntermConstantUnion(tempConstArray, returnType);
2056 tempNode->setLine(loc);
2057 }
2058 return tempNode;
2059}
2060
2061// static
Jamie Madillb1a85f42014-08-19 15:23:24 -04002062TString TIntermTraverser::hash(const TString &name, ShHashFunction64 hashFunction)
2063{
2064 if (hashFunction == NULL || name.empty())
2065 return name;
2066 khronos_uint64_t number = (*hashFunction)(name.c_str(), name.length());
2067 TStringStream stream;
2068 stream << HASHED_NAME_PREFIX << std::hex << number;
2069 TString hashedName = stream.str();
2070 return hashedName;
2071}
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002072
2073void TIntermTraverser::updateTree()
2074{
Olli Etuahoa6f22092015-05-08 18:31:10 +03002075 for (size_t ii = 0; ii < mInsertions.size(); ++ii)
2076 {
2077 const NodeInsertMultipleEntry &insertion = mInsertions[ii];
2078 ASSERT(insertion.parent);
2079 bool inserted = insertion.parent->insertChildNodes(insertion.position, insertion.insertions);
2080 ASSERT(inserted);
2081 UNUSED_ASSERTION_VARIABLE(inserted);
2082 }
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002083 for (size_t ii = 0; ii < mReplacements.size(); ++ii)
2084 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03002085 const NodeUpdateEntry &replacement = mReplacements[ii];
2086 ASSERT(replacement.parent);
2087 bool replaced = replacement.parent->replaceChildNode(
2088 replacement.original, replacement.replacement);
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002089 ASSERT(replaced);
Olli Etuahod57e0db2015-04-24 15:05:08 +03002090 UNUSED_ASSERTION_VARIABLE(replaced);
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002091
Olli Etuahocd94ef92015-04-16 19:18:10 +03002092 if (!replacement.originalBecomesChildOfReplacement)
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002093 {
2094 // In AST traversing, a parent is visited before its children.
Olli Etuahocd94ef92015-04-16 19:18:10 +03002095 // After we replace a node, if its immediate child is to
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002096 // be replaced, we need to make sure we don't update the replaced
2097 // node; instead, we update the replacement node.
2098 for (size_t jj = ii + 1; jj < mReplacements.size(); ++jj)
2099 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03002100 NodeUpdateEntry &replacement2 = mReplacements[jj];
2101 if (replacement2.parent == replacement.original)
2102 replacement2.parent = replacement.replacement;
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002103 }
2104 }
2105 }
Olli Etuahofc0e2bc2015-04-16 13:39:56 +03002106 for (size_t ii = 0; ii < mMultiReplacements.size(); ++ii)
2107 {
2108 const NodeReplaceWithMultipleEntry &replacement = mMultiReplacements[ii];
2109 ASSERT(replacement.parent);
2110 bool replaced = replacement.parent->replaceChildNodeWithMultiple(
2111 replacement.original, replacement.replacements);
2112 ASSERT(replaced);
Olli Etuahod57e0db2015-04-24 15:05:08 +03002113 UNUSED_ASSERTION_VARIABLE(replaced);
Olli Etuahofc0e2bc2015-04-16 13:39:56 +03002114 }
Olli Etuahod4f303e2015-05-20 17:09:06 +03002115
2116 mInsertions.clear();
2117 mReplacements.clear();
2118 mMultiReplacements.clear();
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002119}