blob: a8018a4e8e46576e054407726c3ca8265118660d [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>
16
17#include "compiler/translator/HashNames.h"
18#include "compiler/translator/IntermNode.h"
19#include "compiler/translator/SymbolTable.h"
20
21namespace
22{
23
Arun Patole9dea48f2015-04-02 11:45:09 +053024const float kPi = 3.14159265358979323846f;
25const float kDegreesToRadiansMultiplier = kPi / 180.0f;
26const float kRadiansToDegreesMultiplier = 180.0f / kPi;
27
Jamie Madillb1a85f42014-08-19 15:23:24 -040028TPrecision GetHigherPrecision(TPrecision left, TPrecision right)
29{
30 return left > right ? left : right;
31}
32
33bool ValidateMultiplication(TOperator op, const TType &left, const TType &right)
34{
35 switch (op)
36 {
37 case EOpMul:
38 case EOpMulAssign:
39 return left.getNominalSize() == right.getNominalSize() &&
40 left.getSecondarySize() == right.getSecondarySize();
41 case EOpVectorTimesScalar:
42 case EOpVectorTimesScalarAssign:
43 return true;
44 case EOpVectorTimesMatrix:
45 return left.getNominalSize() == right.getRows();
46 case EOpVectorTimesMatrixAssign:
47 return left.getNominalSize() == right.getRows() &&
48 left.getNominalSize() == right.getCols();
49 case EOpMatrixTimesVector:
50 return left.getCols() == right.getNominalSize();
51 case EOpMatrixTimesScalar:
52 case EOpMatrixTimesScalarAssign:
53 return true;
54 case EOpMatrixTimesMatrix:
55 return left.getCols() == right.getRows();
56 case EOpMatrixTimesMatrixAssign:
57 return left.getCols() == right.getCols() &&
58 left.getRows() == right.getRows();
59
60 default:
61 UNREACHABLE();
62 return false;
63 }
64}
65
66bool CompareStructure(const TType& leftNodeType,
67 ConstantUnion *rightUnionArray,
68 ConstantUnion *leftUnionArray);
69
70bool CompareStruct(const TType &leftNodeType,
71 ConstantUnion *rightUnionArray,
72 ConstantUnion *leftUnionArray)
73{
74 const TFieldList &fields = leftNodeType.getStruct()->fields();
75
76 size_t structSize = fields.size();
77 size_t index = 0;
78
79 for (size_t j = 0; j < structSize; j++)
80 {
81 size_t size = fields[j]->type()->getObjectSize();
82 for (size_t i = 0; i < size; i++)
83 {
84 if (fields[j]->type()->getBasicType() == EbtStruct)
85 {
86 if (!CompareStructure(*fields[j]->type(),
87 &rightUnionArray[index],
88 &leftUnionArray[index]))
89 {
90 return false;
91 }
92 }
93 else
94 {
95 if (leftUnionArray[index] != rightUnionArray[index])
96 return false;
97 index++;
98 }
99 }
100 }
101 return true;
102}
103
104bool CompareStructure(const TType &leftNodeType,
105 ConstantUnion *rightUnionArray,
106 ConstantUnion *leftUnionArray)
107{
108 if (leftNodeType.isArray())
109 {
110 TType typeWithoutArrayness = leftNodeType;
111 typeWithoutArrayness.clearArrayness();
112
113 size_t arraySize = leftNodeType.getArraySize();
114
115 for (size_t i = 0; i < arraySize; ++i)
116 {
117 size_t offset = typeWithoutArrayness.getObjectSize() * i;
118 if (!CompareStruct(typeWithoutArrayness,
119 &rightUnionArray[offset],
120 &leftUnionArray[offset]))
121 {
122 return false;
123 }
124 }
125 }
126 else
127 {
128 return CompareStruct(leftNodeType, rightUnionArray, leftUnionArray);
129 }
130 return true;
131}
132
133} // namespace anonymous
134
135
136////////////////////////////////////////////////////////////////
137//
138// Member functions of the nodes used for building the tree.
139//
140////////////////////////////////////////////////////////////////
141
Olli Etuahod2a67b92014-10-21 16:42:57 +0300142void TIntermTyped::setTypePreservePrecision(const TType &t)
143{
144 TPrecision precision = getPrecision();
145 mType = t;
146 ASSERT(mType.getBasicType() != EbtBool || precision == EbpUndefined);
147 mType.setPrecision(precision);
148}
149
Jamie Madillb1a85f42014-08-19 15:23:24 -0400150#define REPLACE_IF_IS(node, type, original, replacement) \
151 if (node == original) { \
152 node = static_cast<type *>(replacement); \
153 return true; \
154 }
155
156bool TIntermLoop::replaceChildNode(
157 TIntermNode *original, TIntermNode *replacement)
158{
159 REPLACE_IF_IS(mInit, TIntermNode, original, replacement);
160 REPLACE_IF_IS(mCond, TIntermTyped, original, replacement);
161 REPLACE_IF_IS(mExpr, TIntermTyped, original, replacement);
162 REPLACE_IF_IS(mBody, TIntermNode, original, replacement);
163 return false;
164}
165
Jamie Madillb1a85f42014-08-19 15:23:24 -0400166bool TIntermBranch::replaceChildNode(
167 TIntermNode *original, TIntermNode *replacement)
168{
169 REPLACE_IF_IS(mExpression, TIntermTyped, original, replacement);
170 return false;
171}
172
Jamie Madillb1a85f42014-08-19 15:23:24 -0400173bool TIntermBinary::replaceChildNode(
174 TIntermNode *original, TIntermNode *replacement)
175{
176 REPLACE_IF_IS(mLeft, TIntermTyped, original, replacement);
177 REPLACE_IF_IS(mRight, TIntermTyped, original, replacement);
178 return false;
179}
180
Jamie Madillb1a85f42014-08-19 15:23:24 -0400181bool TIntermUnary::replaceChildNode(
182 TIntermNode *original, TIntermNode *replacement)
183{
184 REPLACE_IF_IS(mOperand, TIntermTyped, original, replacement);
185 return false;
186}
187
Jamie Madillb1a85f42014-08-19 15:23:24 -0400188bool TIntermAggregate::replaceChildNode(
189 TIntermNode *original, TIntermNode *replacement)
190{
191 for (size_t ii = 0; ii < mSequence.size(); ++ii)
192 {
193 REPLACE_IF_IS(mSequence[ii], TIntermNode, original, replacement);
194 }
195 return false;
196}
197
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300198bool TIntermAggregate::replaceChildNodeWithMultiple(TIntermNode *original, TIntermSequence replacements)
199{
200 for (auto it = mSequence.begin(); it < mSequence.end(); ++it)
201 {
202 if (*it == original)
203 {
204 it = mSequence.erase(it);
205 it = mSequence.insert(it, replacements.begin(), replacements.end());
206 return true;
207 }
208 }
209 return false;
210}
211
Olli Etuahod2a67b92014-10-21 16:42:57 +0300212void TIntermAggregate::setPrecisionFromChildren()
213{
214 if (getBasicType() == EbtBool)
215 {
216 mType.setPrecision(EbpUndefined);
217 return;
218 }
219
220 TPrecision precision = EbpUndefined;
221 TIntermSequence::iterator childIter = mSequence.begin();
222 while (childIter != mSequence.end())
223 {
224 TIntermTyped *typed = (*childIter)->getAsTyped();
225 if (typed)
226 precision = GetHigherPrecision(typed->getPrecision(), precision);
227 ++childIter;
228 }
229 mType.setPrecision(precision);
230}
231
232void TIntermAggregate::setBuiltInFunctionPrecision()
233{
234 // All built-ins returning bool should be handled as ops, not functions.
235 ASSERT(getBasicType() != EbtBool);
236
237 TPrecision precision = EbpUndefined;
238 TIntermSequence::iterator childIter = mSequence.begin();
239 while (childIter != mSequence.end())
240 {
241 TIntermTyped *typed = (*childIter)->getAsTyped();
242 // ESSL spec section 8: texture functions get their precision from the sampler.
243 if (typed && IsSampler(typed->getBasicType()))
244 {
245 precision = typed->getPrecision();
246 break;
247 }
248 ++childIter;
249 }
250 // ESSL 3.0 spec section 8: textureSize always gets highp precision.
251 // All other functions that take a sampler are assumed to be texture functions.
252 if (mName.find("textureSize") == 0)
253 mType.setPrecision(EbpHigh);
254 else
255 mType.setPrecision(precision);
256}
257
Jamie Madillb1a85f42014-08-19 15:23:24 -0400258bool TIntermSelection::replaceChildNode(
259 TIntermNode *original, TIntermNode *replacement)
260{
261 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
262 REPLACE_IF_IS(mTrueBlock, TIntermNode, original, replacement);
263 REPLACE_IF_IS(mFalseBlock, TIntermNode, original, replacement);
264 return false;
265}
266
Olli Etuahoa3a36662015-02-17 13:46:51 +0200267bool TIntermSwitch::replaceChildNode(
268 TIntermNode *original, TIntermNode *replacement)
269{
270 REPLACE_IF_IS(mInit, TIntermTyped, original, replacement);
271 REPLACE_IF_IS(mStatementList, TIntermAggregate, original, replacement);
272 return false;
273}
274
275bool TIntermCase::replaceChildNode(
276 TIntermNode *original, TIntermNode *replacement)
277{
278 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
279 return false;
280}
281
Jamie Madillb1a85f42014-08-19 15:23:24 -0400282//
283// Say whether or not an operation node changes the value of a variable.
284//
285bool TIntermOperator::isAssignment() const
286{
287 switch (mOp)
288 {
289 case EOpPostIncrement:
290 case EOpPostDecrement:
291 case EOpPreIncrement:
292 case EOpPreDecrement:
293 case EOpAssign:
294 case EOpAddAssign:
295 case EOpSubAssign:
296 case EOpMulAssign:
297 case EOpVectorTimesMatrixAssign:
298 case EOpVectorTimesScalarAssign:
299 case EOpMatrixTimesScalarAssign:
300 case EOpMatrixTimesMatrixAssign:
301 case EOpDivAssign:
Olli Etuahoff805cc2015-02-13 10:59:34 +0200302 case EOpIModAssign:
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200303 case EOpBitShiftLeftAssign:
304 case EOpBitShiftRightAssign:
305 case EOpBitwiseAndAssign:
306 case EOpBitwiseXorAssign:
307 case EOpBitwiseOrAssign:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400308 return true;
309 default:
310 return false;
311 }
312}
313
314//
315// returns true if the operator is for one of the constructors
316//
317bool TIntermOperator::isConstructor() const
318{
319 switch (mOp)
320 {
321 case EOpConstructVec2:
322 case EOpConstructVec3:
323 case EOpConstructVec4:
324 case EOpConstructMat2:
325 case EOpConstructMat3:
326 case EOpConstructMat4:
327 case EOpConstructFloat:
328 case EOpConstructIVec2:
329 case EOpConstructIVec3:
330 case EOpConstructIVec4:
331 case EOpConstructInt:
332 case EOpConstructUVec2:
333 case EOpConstructUVec3:
334 case EOpConstructUVec4:
335 case EOpConstructUInt:
336 case EOpConstructBVec2:
337 case EOpConstructBVec3:
338 case EOpConstructBVec4:
339 case EOpConstructBool:
340 case EOpConstructStruct:
341 return true;
342 default:
343 return false;
344 }
345}
346
347//
348// Make sure the type of a unary operator is appropriate for its
349// combination of operation and operand type.
350//
Olli Etuahof6c694b2015-03-26 14:50:53 +0200351void TIntermUnary::promote(const TType *funcReturnType)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400352{
353 switch (mOp)
354 {
Olli Etuahodca3e792015-03-26 13:24:04 +0200355 case EOpFloatBitsToInt:
356 case EOpFloatBitsToUint:
Olli Etuahoe8d2c072015-01-08 16:33:54 +0200357 case EOpIntBitsToFloat:
358 case EOpUintBitsToFloat:
Olli Etuahodca3e792015-03-26 13:24:04 +0200359 case EOpPackSnorm2x16:
360 case EOpPackUnorm2x16:
361 case EOpPackHalf2x16:
Olli Etuaho7700ff62015-01-15 12:16:29 +0200362 case EOpUnpackSnorm2x16:
363 case EOpUnpackUnorm2x16:
Olli Etuahodca3e792015-03-26 13:24:04 +0200364 mType.setPrecision(EbpHigh);
Arun Patole6b19d762015-02-19 09:40:39 +0530365 break;
Olli Etuahodca3e792015-03-26 13:24:04 +0200366 case EOpUnpackHalf2x16:
367 mType.setPrecision(EbpMedium);
368 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400369 default:
Olli Etuahodca3e792015-03-26 13:24:04 +0200370 setType(mOperand->getType());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400371 }
372
Olli Etuahof6c694b2015-03-26 14:50:53 +0200373 if (funcReturnType != nullptr)
374 {
375 if (funcReturnType->getBasicType() == EbtBool)
376 {
377 // Bool types should not have precision.
378 setType(*funcReturnType);
379 }
380 else
381 {
382 // Precision of the node has been set based on the operand.
383 setTypePreservePrecision(*funcReturnType);
384 }
385 }
386
Jamie Madillb1a85f42014-08-19 15:23:24 -0400387 mType.setQualifier(EvqTemporary);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400388}
389
390//
391// Establishes the type of the resultant operation, as well as
392// makes the operator the correct one for the operands.
393//
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200394// For lots of operations it should already be established that the operand
395// combination is valid, but returns false if operator can't work on operands.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400396//
397bool TIntermBinary::promote(TInfoSink &infoSink)
398{
Olli Etuahoe79904c2015-03-18 16:56:42 +0200399 ASSERT(mLeft->isArray() == mRight->isArray());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400400
Jamie Madillb1a85f42014-08-19 15:23:24 -0400401 //
402 // Base assumption: just make the type the same as the left
403 // operand. Then only deviations from this need be coded.
404 //
405 setType(mLeft->getType());
406
407 // The result gets promoted to the highest precision.
408 TPrecision higherPrecision = GetHigherPrecision(
409 mLeft->getPrecision(), mRight->getPrecision());
410 getTypePointer()->setPrecision(higherPrecision);
411
412 // Binary operations results in temporary variables unless both
413 // operands are const.
414 if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst)
415 {
416 getTypePointer()->setQualifier(EvqTemporary);
417 }
418
419 const int nominalSize =
420 std::max(mLeft->getNominalSize(), mRight->getNominalSize());
421
422 //
423 // All scalars or structs. Code after this test assumes this case is removed!
424 //
425 if (nominalSize == 1)
426 {
427 switch (mOp)
428 {
429 //
430 // Promote to conditional
431 //
432 case EOpEqual:
433 case EOpNotEqual:
434 case EOpLessThan:
435 case EOpGreaterThan:
436 case EOpLessThanEqual:
437 case EOpGreaterThanEqual:
438 setType(TType(EbtBool, EbpUndefined));
439 break;
440
441 //
442 // And and Or operate on conditionals
443 //
444 case EOpLogicalAnd:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200445 case EOpLogicalXor:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400446 case EOpLogicalOr:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200447 ASSERT(mLeft->getBasicType() == EbtBool && mRight->getBasicType() == EbtBool);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400448 setType(TType(EbtBool, EbpUndefined));
449 break;
450
451 default:
452 break;
453 }
454 return true;
455 }
456
457 // If we reach here, at least one of the operands is vector or matrix.
458 // The other operand could be a scalar, vector, or matrix.
459 // Can these two operands be combined?
460 //
461 TBasicType basicType = mLeft->getBasicType();
462 switch (mOp)
463 {
464 case EOpMul:
465 if (!mLeft->isMatrix() && mRight->isMatrix())
466 {
467 if (mLeft->isVector())
468 {
469 mOp = EOpVectorTimesMatrix;
470 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700471 static_cast<unsigned char>(mRight->getCols()), 1));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400472 }
473 else
474 {
475 mOp = EOpMatrixTimesScalar;
476 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700477 static_cast<unsigned char>(mRight->getCols()), static_cast<unsigned char>(mRight->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400478 }
479 }
480 else if (mLeft->isMatrix() && !mRight->isMatrix())
481 {
482 if (mRight->isVector())
483 {
484 mOp = EOpMatrixTimesVector;
485 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700486 static_cast<unsigned char>(mLeft->getRows()), 1));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400487 }
488 else
489 {
490 mOp = EOpMatrixTimesScalar;
491 }
492 }
493 else if (mLeft->isMatrix() && mRight->isMatrix())
494 {
495 mOp = EOpMatrixTimesMatrix;
496 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700497 static_cast<unsigned char>(mRight->getCols()), static_cast<unsigned char>(mLeft->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400498 }
499 else if (!mLeft->isMatrix() && !mRight->isMatrix())
500 {
501 if (mLeft->isVector() && mRight->isVector())
502 {
503 // leave as component product
504 }
505 else if (mLeft->isVector() || mRight->isVector())
506 {
507 mOp = EOpVectorTimesScalar;
508 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700509 static_cast<unsigned char>(nominalSize), 1));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400510 }
511 }
512 else
513 {
514 infoSink.info.message(EPrefixInternalError, getLine(),
515 "Missing elses");
516 return false;
517 }
518
519 if (!ValidateMultiplication(mOp, mLeft->getType(), mRight->getType()))
520 {
521 return false;
522 }
523 break;
524
525 case EOpMulAssign:
526 if (!mLeft->isMatrix() && mRight->isMatrix())
527 {
528 if (mLeft->isVector())
529 {
530 mOp = EOpVectorTimesMatrixAssign;
531 }
532 else
533 {
534 return false;
535 }
536 }
537 else if (mLeft->isMatrix() && !mRight->isMatrix())
538 {
539 if (mRight->isVector())
540 {
541 return false;
542 }
543 else
544 {
545 mOp = EOpMatrixTimesScalarAssign;
546 }
547 }
548 else if (mLeft->isMatrix() && mRight->isMatrix())
549 {
550 mOp = EOpMatrixTimesMatrixAssign;
551 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700552 static_cast<unsigned char>(mRight->getCols()), static_cast<unsigned char>(mLeft->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400553 }
554 else if (!mLeft->isMatrix() && !mRight->isMatrix())
555 {
556 if (mLeft->isVector() && mRight->isVector())
557 {
558 // leave as component product
559 }
560 else if (mLeft->isVector() || mRight->isVector())
561 {
562 if (!mLeft->isVector())
563 return false;
564 mOp = EOpVectorTimesScalarAssign;
565 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700566 static_cast<unsigned char>(mLeft->getNominalSize()), 1));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400567 }
568 }
569 else
570 {
571 infoSink.info.message(EPrefixInternalError, getLine(),
572 "Missing elses");
573 return false;
574 }
575
576 if (!ValidateMultiplication(mOp, mLeft->getType(), mRight->getType()))
577 {
578 return false;
579 }
580 break;
581
582 case EOpAssign:
583 case EOpInitialize:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200584 // No more additional checks are needed.
585 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
586 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
587 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400588 case EOpAdd:
589 case EOpSub:
590 case EOpDiv:
Olli Etuahoff805cc2015-02-13 10:59:34 +0200591 case EOpIMod:
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200592 case EOpBitShiftLeft:
593 case EOpBitShiftRight:
594 case EOpBitwiseAnd:
595 case EOpBitwiseXor:
596 case EOpBitwiseOr:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400597 case EOpAddAssign:
598 case EOpSubAssign:
599 case EOpDivAssign:
Olli Etuahoff805cc2015-02-13 10:59:34 +0200600 case EOpIModAssign:
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200601 case EOpBitShiftLeftAssign:
602 case EOpBitShiftRightAssign:
603 case EOpBitwiseAndAssign:
604 case EOpBitwiseXorAssign:
605 case EOpBitwiseOrAssign:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400606 if ((mLeft->isMatrix() && mRight->isVector()) ||
607 (mLeft->isVector() && mRight->isMatrix()))
608 {
609 return false;
610 }
611
612 // Are the sizes compatible?
613 if (mLeft->getNominalSize() != mRight->getNominalSize() ||
614 mLeft->getSecondarySize() != mRight->getSecondarySize())
615 {
Olli Etuaho6c850472014-12-02 16:23:17 +0200616 // If the nominal sizes of operands do not match:
617 // One of them must be a scalar.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400618 if (!mLeft->isScalar() && !mRight->isScalar())
619 return false;
620
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200621 // In the case of compound assignment other than multiply-assign,
622 // the right side needs to be a scalar. Otherwise a vector/matrix
623 // would be assigned to a scalar. A scalar can't be shifted by a
624 // vector either.
Olli Etuaho6c850472014-12-02 16:23:17 +0200625 if (!mRight->isScalar() &&
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200626 (isAssignment() ||
627 mOp == EOpBitShiftLeft ||
628 mOp == EOpBitShiftRight))
Olli Etuaho6c850472014-12-02 16:23:17 +0200629 return false;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400630 }
631
632 {
633 const int secondarySize = std::max(
634 mLeft->getSecondarySize(), mRight->getSecondarySize());
635 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700636 static_cast<unsigned char>(nominalSize), static_cast<unsigned char>(secondarySize)));
Olli Etuahoe79904c2015-03-18 16:56:42 +0200637 if (mLeft->isArray())
638 {
639 ASSERT(mLeft->getArraySize() == mRight->getArraySize());
640 mType.setArraySize(mLeft->getArraySize());
641 }
Jamie Madillb1a85f42014-08-19 15:23:24 -0400642 }
643 break;
644
645 case EOpEqual:
646 case EOpNotEqual:
647 case EOpLessThan:
648 case EOpGreaterThan:
649 case EOpLessThanEqual:
650 case EOpGreaterThanEqual:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200651 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
652 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400653 setType(TType(EbtBool, EbpUndefined));
654 break;
655
656 default:
657 return false;
658 }
659 return true;
660}
661
662//
663// The fold functions see if an operation on a constant can be done in place,
664// without generating run-time code.
665//
666// Returns the node to keep using, which may or may not be the node passed in.
667//
668TIntermTyped *TIntermConstantUnion::fold(
669 TOperator op, TIntermTyped *constantNode, TInfoSink &infoSink)
670{
671 ConstantUnion *unionArray = getUnionArrayPointer();
672
673 if (!unionArray)
Arun Patolefddc2112015-04-22 13:28:10 +0530674 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400675
676 size_t objectSize = getType().getObjectSize();
677
678 if (constantNode)
679 {
680 // binary operations
681 TIntermConstantUnion *node = constantNode->getAsConstantUnion();
682 ConstantUnion *rightUnionArray = node->getUnionArrayPointer();
683 TType returnType = getType();
684
685 if (!rightUnionArray)
Arun Patolefddc2112015-04-22 13:28:10 +0530686 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400687
688 // for a case like float f = 1.2 + vec4(2,3,4,5);
689 if (constantNode->getType().getObjectSize() == 1 && objectSize > 1)
690 {
691 rightUnionArray = new ConstantUnion[objectSize];
692 for (size_t i = 0; i < objectSize; ++i)
693 {
694 rightUnionArray[i] = *node->getUnionArrayPointer();
695 }
696 returnType = getType();
697 }
698 else if (constantNode->getType().getObjectSize() > 1 && objectSize == 1)
699 {
700 // for a case like float f = vec4(2,3,4,5) + 1.2;
701 unionArray = new ConstantUnion[constantNode->getType().getObjectSize()];
702 for (size_t i = 0; i < constantNode->getType().getObjectSize(); ++i)
703 {
704 unionArray[i] = *getUnionArrayPointer();
705 }
706 returnType = node->getType();
707 objectSize = constantNode->getType().getObjectSize();
708 }
709
710 ConstantUnion *tempConstArray = NULL;
711 TIntermConstantUnion *tempNode;
712
713 bool boolNodeFlag = false;
714 switch(op)
715 {
716 case EOpAdd:
717 tempConstArray = new ConstantUnion[objectSize];
718 for (size_t i = 0; i < objectSize; i++)
719 tempConstArray[i] = unionArray[i] + rightUnionArray[i];
720 break;
721 case EOpSub:
722 tempConstArray = new ConstantUnion[objectSize];
723 for (size_t i = 0; i < objectSize; i++)
724 tempConstArray[i] = unionArray[i] - rightUnionArray[i];
725 break;
726
727 case EOpMul:
728 case EOpVectorTimesScalar:
729 case EOpMatrixTimesScalar:
730 tempConstArray = new ConstantUnion[objectSize];
731 for (size_t i = 0; i < objectSize; i++)
732 tempConstArray[i] = unionArray[i] * rightUnionArray[i];
733 break;
734
735 case EOpMatrixTimesMatrix:
736 {
737 if (getType().getBasicType() != EbtFloat ||
738 node->getBasicType() != EbtFloat)
739 {
740 infoSink.info.message(
741 EPrefixInternalError, getLine(),
742 "Constant Folding cannot be done for matrix multiply");
Arun Patolefddc2112015-04-22 13:28:10 +0530743 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400744 }
745
746 const int leftCols = getCols();
747 const int leftRows = getRows();
748 const int rightCols = constantNode->getType().getCols();
749 const int rightRows = constantNode->getType().getRows();
750 const int resultCols = rightCols;
751 const int resultRows = leftRows;
752
753 tempConstArray = new ConstantUnion[resultCols*resultRows];
754 for (int row = 0; row < resultRows; row++)
755 {
756 for (int column = 0; column < resultCols; column++)
757 {
758 tempConstArray[resultRows * column + row].setFConst(0.0f);
759 for (int i = 0; i < leftCols; i++)
760 {
761 tempConstArray[resultRows * column + row].setFConst(
762 tempConstArray[resultRows * column + row].getFConst() +
763 unionArray[i * leftRows + row].getFConst() *
764 rightUnionArray[column * rightRows + i].getFConst());
765 }
766 }
767 }
768
769 // update return type for matrix product
Minmin Gong794e0002015-04-07 18:31:54 -0700770 returnType.setPrimarySize(static_cast<unsigned char>(resultCols));
771 returnType.setSecondarySize(static_cast<unsigned char>(resultRows));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400772 }
773 break;
774
775 case EOpDiv:
Olli Etuahoff805cc2015-02-13 10:59:34 +0200776 case EOpIMod:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400777 {
778 tempConstArray = new ConstantUnion[objectSize];
779 for (size_t i = 0; i < objectSize; i++)
780 {
781 switch (getType().getBasicType())
782 {
783 case EbtFloat:
784 if (rightUnionArray[i] == 0.0f)
785 {
786 infoSink.info.message(
787 EPrefixWarning, getLine(),
788 "Divide by zero error during constant folding");
789 tempConstArray[i].setFConst(
790 unionArray[i].getFConst() < 0 ? -FLT_MAX : FLT_MAX);
791 }
792 else
793 {
Olli Etuaho3eab00a2015-02-12 16:02:39 +0200794 ASSERT(op == EOpDiv);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400795 tempConstArray[i].setFConst(
796 unionArray[i].getFConst() /
797 rightUnionArray[i].getFConst());
798 }
799 break;
800
801 case EbtInt:
802 if (rightUnionArray[i] == 0)
803 {
804 infoSink.info.message(
805 EPrefixWarning, getLine(),
806 "Divide by zero error during constant folding");
807 tempConstArray[i].setIConst(INT_MAX);
808 }
809 else
810 {
Olli Etuaho3eab00a2015-02-12 16:02:39 +0200811 if (op == EOpDiv)
812 {
813 tempConstArray[i].setIConst(
814 unionArray[i].getIConst() /
815 rightUnionArray[i].getIConst());
816 }
817 else
818 {
819 ASSERT(op == EOpIMod);
820 tempConstArray[i].setIConst(
821 unionArray[i].getIConst() %
822 rightUnionArray[i].getIConst());
823 }
Jamie Madillb1a85f42014-08-19 15:23:24 -0400824 }
825 break;
826
827 case EbtUInt:
828 if (rightUnionArray[i] == 0)
829 {
830 infoSink.info.message(
831 EPrefixWarning, getLine(),
832 "Divide by zero error during constant folding");
833 tempConstArray[i].setUConst(UINT_MAX);
834 }
835 else
836 {
Olli Etuaho3eab00a2015-02-12 16:02:39 +0200837 if (op == EOpDiv)
838 {
839 tempConstArray[i].setUConst(
840 unionArray[i].getUConst() /
841 rightUnionArray[i].getUConst());
842 }
843 else
844 {
845 ASSERT(op == EOpIMod);
846 tempConstArray[i].setUConst(
847 unionArray[i].getUConst() %
848 rightUnionArray[i].getUConst());
849 }
Jamie Madillb1a85f42014-08-19 15:23:24 -0400850 }
851 break;
852
853 default:
854 infoSink.info.message(
855 EPrefixInternalError, getLine(),
856 "Constant folding cannot be done for \"/\"");
Arun Patolefddc2112015-04-22 13:28:10 +0530857 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400858 }
859 }
860 }
861 break;
862
863 case EOpMatrixTimesVector:
864 {
865 if (node->getBasicType() != EbtFloat)
866 {
867 infoSink.info.message(
868 EPrefixInternalError, getLine(),
869 "Constant Folding cannot be done for matrix times vector");
Arun Patolefddc2112015-04-22 13:28:10 +0530870 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400871 }
872
873 const int matrixCols = getCols();
874 const int matrixRows = getRows();
875
876 tempConstArray = new ConstantUnion[matrixRows];
877
878 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
879 {
880 tempConstArray[matrixRow].setFConst(0.0f);
881 for (int col = 0; col < matrixCols; col++)
882 {
883 tempConstArray[matrixRow].setFConst(
884 tempConstArray[matrixRow].getFConst() +
885 unionArray[col * matrixRows + matrixRow].getFConst() *
886 rightUnionArray[col].getFConst());
887 }
888 }
889
890 returnType = node->getType();
Minmin Gong794e0002015-04-07 18:31:54 -0700891 returnType.setPrimarySize(static_cast<unsigned char>(matrixRows));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400892
893 tempNode = new TIntermConstantUnion(tempConstArray, returnType);
894 tempNode->setLine(getLine());
895
896 return tempNode;
897 }
898
899 case EOpVectorTimesMatrix:
900 {
901 if (getType().getBasicType() != EbtFloat)
902 {
903 infoSink.info.message(
904 EPrefixInternalError, getLine(),
905 "Constant Folding cannot be done for vector times matrix");
Arun Patolefddc2112015-04-22 13:28:10 +0530906 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400907 }
908
909 const int matrixCols = constantNode->getType().getCols();
910 const int matrixRows = constantNode->getType().getRows();
911
912 tempConstArray = new ConstantUnion[matrixCols];
913
914 for (int matrixCol = 0; matrixCol < matrixCols; matrixCol++)
915 {
916 tempConstArray[matrixCol].setFConst(0.0f);
917 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
918 {
919 tempConstArray[matrixCol].setFConst(
920 tempConstArray[matrixCol].getFConst() +
921 unionArray[matrixRow].getFConst() *
922 rightUnionArray[matrixCol * matrixRows + matrixRow].getFConst());
923 }
924 }
925
Minmin Gong794e0002015-04-07 18:31:54 -0700926 returnType.setPrimarySize(static_cast<unsigned char>(matrixCols));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400927 }
928 break;
929
930 case EOpLogicalAnd:
931 // this code is written for possible future use,
932 // will not get executed currently
933 {
934 tempConstArray = new ConstantUnion[objectSize];
935 for (size_t i = 0; i < objectSize; i++)
936 {
937 tempConstArray[i] = unionArray[i] && rightUnionArray[i];
938 }
939 }
940 break;
941
942 case EOpLogicalOr:
943 // this code is written for possible future use,
944 // will not get executed currently
945 {
946 tempConstArray = new ConstantUnion[objectSize];
947 for (size_t i = 0; i < objectSize; i++)
948 {
949 tempConstArray[i] = unionArray[i] || rightUnionArray[i];
950 }
951 }
952 break;
953
954 case EOpLogicalXor:
955 {
956 tempConstArray = new ConstantUnion[objectSize];
957 for (size_t i = 0; i < objectSize; i++)
958 {
959 switch (getType().getBasicType())
960 {
961 case EbtBool:
962 tempConstArray[i].setBConst(
963 unionArray[i] == rightUnionArray[i] ? false : true);
964 break;
965 default:
966 UNREACHABLE();
967 break;
968 }
969 }
970 }
971 break;
972
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200973 case EOpBitwiseAnd:
974 tempConstArray = new ConstantUnion[objectSize];
975 for (size_t i = 0; i < objectSize; i++)
976 tempConstArray[i] = unionArray[i] & rightUnionArray[i];
977 break;
978 case EOpBitwiseXor:
979 tempConstArray = new ConstantUnion[objectSize];
980 for (size_t i = 0; i < objectSize; i++)
981 tempConstArray[i] = unionArray[i] ^ rightUnionArray[i];
982 break;
983 case EOpBitwiseOr:
984 tempConstArray = new ConstantUnion[objectSize];
985 for (size_t i = 0; i < objectSize; i++)
986 tempConstArray[i] = unionArray[i] | rightUnionArray[i];
987 break;
988 case EOpBitShiftLeft:
989 tempConstArray = new ConstantUnion[objectSize];
990 for (size_t i = 0; i < objectSize; i++)
991 tempConstArray[i] = unionArray[i] << rightUnionArray[i];
992 break;
993 case EOpBitShiftRight:
994 tempConstArray = new ConstantUnion[objectSize];
995 for (size_t i = 0; i < objectSize; i++)
996 tempConstArray[i] = unionArray[i] >> rightUnionArray[i];
997 break;
998
Jamie Madillb1a85f42014-08-19 15:23:24 -0400999 case EOpLessThan:
1000 ASSERT(objectSize == 1);
1001 tempConstArray = new ConstantUnion[1];
1002 tempConstArray->setBConst(*unionArray < *rightUnionArray);
1003 returnType = TType(EbtBool, EbpUndefined, EvqConst);
1004 break;
1005
1006 case EOpGreaterThan:
1007 ASSERT(objectSize == 1);
1008 tempConstArray = new ConstantUnion[1];
1009 tempConstArray->setBConst(*unionArray > *rightUnionArray);
1010 returnType = TType(EbtBool, EbpUndefined, EvqConst);
1011 break;
1012
1013 case EOpLessThanEqual:
1014 {
1015 ASSERT(objectSize == 1);
1016 ConstantUnion constant;
1017 constant.setBConst(*unionArray > *rightUnionArray);
1018 tempConstArray = new ConstantUnion[1];
1019 tempConstArray->setBConst(!constant.getBConst());
1020 returnType = TType(EbtBool, EbpUndefined, EvqConst);
1021 break;
1022 }
1023
1024 case EOpGreaterThanEqual:
1025 {
1026 ASSERT(objectSize == 1);
1027 ConstantUnion constant;
1028 constant.setBConst(*unionArray < *rightUnionArray);
1029 tempConstArray = new ConstantUnion[1];
1030 tempConstArray->setBConst(!constant.getBConst());
1031 returnType = TType(EbtBool, EbpUndefined, EvqConst);
1032 break;
1033 }
1034
1035 case EOpEqual:
1036 if (getType().getBasicType() == EbtStruct)
1037 {
1038 if (!CompareStructure(node->getType(),
1039 node->getUnionArrayPointer(),
1040 unionArray))
1041 {
1042 boolNodeFlag = true;
1043 }
1044 }
1045 else
1046 {
1047 for (size_t i = 0; i < objectSize; i++)
1048 {
1049 if (unionArray[i] != rightUnionArray[i])
1050 {
1051 boolNodeFlag = true;
1052 break; // break out of for loop
1053 }
1054 }
1055 }
1056
1057 tempConstArray = new ConstantUnion[1];
1058 if (!boolNodeFlag)
1059 {
1060 tempConstArray->setBConst(true);
1061 }
1062 else
1063 {
1064 tempConstArray->setBConst(false);
1065 }
1066
1067 tempNode = new TIntermConstantUnion(
1068 tempConstArray, TType(EbtBool, EbpUndefined, EvqConst));
1069 tempNode->setLine(getLine());
1070
1071 return tempNode;
1072
1073 case EOpNotEqual:
1074 if (getType().getBasicType() == EbtStruct)
1075 {
1076 if (CompareStructure(node->getType(),
1077 node->getUnionArrayPointer(),
1078 unionArray))
1079 {
1080 boolNodeFlag = true;
1081 }
1082 }
1083 else
1084 {
1085 for (size_t i = 0; i < objectSize; i++)
1086 {
1087 if (unionArray[i] == rightUnionArray[i])
1088 {
1089 boolNodeFlag = true;
1090 break; // break out of for loop
1091 }
1092 }
1093 }
1094
1095 tempConstArray = new ConstantUnion[1];
1096 if (!boolNodeFlag)
1097 {
1098 tempConstArray->setBConst(true);
1099 }
1100 else
1101 {
1102 tempConstArray->setBConst(false);
1103 }
1104
1105 tempNode = new TIntermConstantUnion(
1106 tempConstArray, TType(EbtBool, EbpUndefined, EvqConst));
1107 tempNode->setLine(getLine());
1108
1109 return tempNode;
1110
1111 default:
1112 infoSink.info.message(
1113 EPrefixInternalError, getLine(),
1114 "Invalid operator for constant folding");
Arun Patolefddc2112015-04-22 13:28:10 +05301115 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001116 }
1117 tempNode = new TIntermConstantUnion(tempConstArray, returnType);
1118 tempNode->setLine(getLine());
1119
1120 return tempNode;
1121 }
1122 else
1123 {
1124 //
1125 // Do unary operations
1126 //
1127 TIntermConstantUnion *newNode = 0;
1128 ConstantUnion* tempConstArray = new ConstantUnion[objectSize];
1129 for (size_t i = 0; i < objectSize; i++)
1130 {
1131 switch(op)
1132 {
1133 case EOpNegative:
1134 switch (getType().getBasicType())
1135 {
1136 case EbtFloat:
1137 tempConstArray[i].setFConst(-unionArray[i].getFConst());
1138 break;
1139 case EbtInt:
1140 tempConstArray[i].setIConst(-unionArray[i].getIConst());
1141 break;
1142 case EbtUInt:
1143 tempConstArray[i].setUConst(static_cast<unsigned int>(
1144 -static_cast<int>(unionArray[i].getUConst())));
1145 break;
1146 default:
1147 infoSink.info.message(
1148 EPrefixInternalError, getLine(),
1149 "Unary operation not folded into constant");
Arun Patolefddc2112015-04-22 13:28:10 +05301150 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001151 }
1152 break;
1153
Zhenyao Mode1e00e2014-10-09 16:55:32 -07001154 case EOpPositive:
1155 switch (getType().getBasicType())
1156 {
1157 case EbtFloat:
1158 tempConstArray[i].setFConst(unionArray[i].getFConst());
1159 break;
1160 case EbtInt:
1161 tempConstArray[i].setIConst(unionArray[i].getIConst());
1162 break;
1163 case EbtUInt:
1164 tempConstArray[i].setUConst(static_cast<unsigned int>(
1165 static_cast<int>(unionArray[i].getUConst())));
1166 break;
1167 default:
1168 infoSink.info.message(
1169 EPrefixInternalError, getLine(),
1170 "Unary operation not folded into constant");
Arun Patolefddc2112015-04-22 13:28:10 +05301171 return nullptr;
Zhenyao Mode1e00e2014-10-09 16:55:32 -07001172 }
1173 break;
1174
Jamie Madillb1a85f42014-08-19 15:23:24 -04001175 case EOpLogicalNot:
1176 // this code is written for possible future use,
1177 // will not get executed currently
1178 switch (getType().getBasicType())
1179 {
1180 case EbtBool:
1181 tempConstArray[i].setBConst(!unionArray[i].getBConst());
1182 break;
1183 default:
1184 infoSink.info.message(
1185 EPrefixInternalError, getLine(),
1186 "Unary operation not folded into constant");
Arun Patolefddc2112015-04-22 13:28:10 +05301187 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001188 }
1189 break;
1190
Olli Etuaho31b5fc62015-01-16 12:13:36 +02001191 case EOpBitwiseNot:
1192 switch (getType().getBasicType())
1193 {
1194 case EbtInt:
1195 tempConstArray[i].setIConst(~unionArray[i].getIConst());
1196 break;
1197 case EbtUInt:
1198 tempConstArray[i].setUConst(~unionArray[i].getUConst());
1199 break;
1200 default:
1201 infoSink.info.message(
1202 EPrefixInternalError, getLine(),
1203 "Unary operation not folded into constant");
Arun Patolefddc2112015-04-22 13:28:10 +05301204 return nullptr;
Olli Etuaho31b5fc62015-01-16 12:13:36 +02001205 }
1206 break;
1207
Arun Patole9dea48f2015-04-02 11:45:09 +05301208 case EOpRadians:
1209 if (getType().getBasicType() == EbtFloat)
1210 {
1211 tempConstArray[i].setFConst(kDegreesToRadiansMultiplier * unionArray[i].getFConst());
1212 break;
1213 }
1214 infoSink.info.message(
1215 EPrefixInternalError, getLine(),
1216 "Unary operation not folded into constant");
1217 return nullptr;
1218
1219 case EOpDegrees:
1220 if (getType().getBasicType() == EbtFloat)
1221 {
1222 tempConstArray[i].setFConst(kRadiansToDegreesMultiplier * unionArray[i].getFConst());
1223 break;
1224 }
1225 infoSink.info.message(
1226 EPrefixInternalError, getLine(),
1227 "Unary operation not folded into constant");
1228 return nullptr;
1229
1230 case EOpSin:
1231 if (!foldFloatTypeUnary(unionArray[i], &sinf, infoSink, &tempConstArray[i]))
1232 return nullptr;
1233 break;
1234
1235 case EOpCos:
1236 if (!foldFloatTypeUnary(unionArray[i], &cosf, infoSink, &tempConstArray[i]))
1237 return nullptr;
1238 break;
1239
1240 case EOpTan:
1241 if (!foldFloatTypeUnary(unionArray[i], &tanf, infoSink, &tempConstArray[i]))
1242 return nullptr;
1243 break;
1244
1245 case EOpAsin:
1246 // For asin(x), results are undefined if |x| > 1, we are choosing to set result to 0.
1247 if (getType().getBasicType() == EbtFloat && fabsf(unionArray[i].getFConst()) > 1.0f)
1248 tempConstArray[i].setFConst(0.0f);
1249 else if (!foldFloatTypeUnary(unionArray[i], &asinf, infoSink, &tempConstArray[i]))
1250 return nullptr;
1251 break;
1252
1253 case EOpAcos:
1254 // For acos(x), results are undefined if |x| > 1, we are choosing to set result to 0.
1255 if (getType().getBasicType() == EbtFloat && fabsf(unionArray[i].getFConst()) > 1.0f)
1256 tempConstArray[i].setFConst(0.0f);
1257 else if (!foldFloatTypeUnary(unionArray[i], &acosf, infoSink, &tempConstArray[i]))
1258 return nullptr;
1259 break;
1260
1261 case EOpAtan:
1262 if (!foldFloatTypeUnary(unionArray[i], &atanf, infoSink, &tempConstArray[i]))
1263 return nullptr;
1264 break;
1265
1266 case EOpSinh:
1267 if (!foldFloatTypeUnary(unionArray[i], &sinhf, infoSink, &tempConstArray[i]))
1268 return nullptr;
1269 break;
1270
1271 case EOpCosh:
1272 if (!foldFloatTypeUnary(unionArray[i], &coshf, infoSink, &tempConstArray[i]))
1273 return nullptr;
1274 break;
1275
1276 case EOpTanh:
1277 if (!foldFloatTypeUnary(unionArray[i], &tanhf, infoSink, &tempConstArray[i]))
1278 return nullptr;
1279 break;
1280
1281 case EOpAsinh:
1282 if (!foldFloatTypeUnary(unionArray[i], &asinhf, infoSink, &tempConstArray[i]))
1283 return nullptr;
1284 break;
1285
1286 case EOpAcosh:
1287 // For acosh(x), results are undefined if x < 1, we are choosing to set result to 0.
1288 if (getType().getBasicType() == EbtFloat && unionArray[i].getFConst() < 1.0f)
1289 tempConstArray[i].setFConst(0.0f);
1290 else if (!foldFloatTypeUnary(unionArray[i], &acoshf, infoSink, &tempConstArray[i]))
1291 return nullptr;
1292 break;
1293
1294 case EOpAtanh:
1295 // For atanh(x), results are undefined if |x| >= 1, we are choosing to set result to 0.
1296 if (getType().getBasicType() == EbtFloat && fabsf(unionArray[i].getFConst()) >= 1.0f)
1297 tempConstArray[i].setFConst(0.0f);
1298 else if (!foldFloatTypeUnary(unionArray[i], &atanhf, infoSink, &tempConstArray[i]))
1299 return nullptr;
1300 break;
1301
Arun Patole97dc22e2015-04-06 17:35:38 +05301302 case EOpAbs:
1303 switch (getType().getBasicType())
1304 {
1305 case EbtFloat:
1306 tempConstArray[i].setFConst(fabsf(unionArray[i].getFConst()));
1307 break;
1308 case EbtInt:
1309 tempConstArray[i].setIConst(abs(unionArray[i].getIConst()));
1310 break;
1311 default:
1312 infoSink.info.message(
1313 EPrefixInternalError, getLine(),
1314 "Unary operation not folded into constant");
1315 return nullptr;
1316 }
1317 break;
1318
1319 case EOpSign:
1320 switch (getType().getBasicType())
1321 {
1322 case EbtFloat:
1323 {
1324 float fConst = unionArray[i].getFConst();
1325 float fResult = 0.0f;
1326 if (fConst > 0.0f)
1327 fResult = 1.0f;
1328 else if (fConst < 0.0f)
1329 fResult = -1.0f;
1330 tempConstArray[i].setFConst(fResult);
1331 }
1332 break;
1333 case EbtInt:
1334 {
1335 int iConst = unionArray[i].getIConst();
1336 int iResult = 0;
1337 if (iConst > 0)
1338 iResult = 1;
1339 else if (iConst < 0)
1340 iResult = -1;
1341 tempConstArray[i].setIConst(iResult);
1342 }
1343 break;
1344 default:
1345 infoSink.info.message(
1346 EPrefixInternalError, getLine(),
1347 "Unary operation not folded into constant");
1348 return nullptr;
1349 }
1350 break;
1351
1352 case EOpFloor:
1353 if (!foldFloatTypeUnary(unionArray[i], &floorf, infoSink, &tempConstArray[i]))
1354 return nullptr;
1355 break;
1356
1357 case EOpTrunc:
1358 if (!foldFloatTypeUnary(unionArray[i], &truncf, infoSink, &tempConstArray[i]))
1359 return nullptr;
1360 break;
1361
1362 case EOpRound:
1363 if (!foldFloatTypeUnary(unionArray[i], &roundf, infoSink, &tempConstArray[i]))
1364 return nullptr;
1365 break;
1366
1367 case EOpRoundEven:
1368 if (getType().getBasicType() == EbtFloat)
1369 {
1370 float x = unionArray[i].getFConst();
1371 float result;
1372 float fractPart = modff(x, &result);
1373 if (fabsf(fractPart) == 0.5f)
1374 result = 2.0f * roundf(x / 2.0f);
1375 else
1376 result = roundf(x);
1377 tempConstArray[i].setFConst(result);
1378 break;
1379 }
1380 infoSink.info.message(
1381 EPrefixInternalError, getLine(),
1382 "Unary operation not folded into constant");
1383 return nullptr;
1384
1385 case EOpCeil:
1386 if (!foldFloatTypeUnary(unionArray[i], &ceilf, infoSink, &tempConstArray[i]))
1387 return nullptr;
1388 break;
1389
1390 case EOpFract:
1391 if (getType().getBasicType() == EbtFloat)
1392 {
1393 float x = unionArray[i].getFConst();
1394 tempConstArray[i].setFConst(x - floorf(x));
1395 break;
1396 }
1397 infoSink.info.message(
1398 EPrefixInternalError, getLine(),
1399 "Unary operation not folded into constant");
1400 return nullptr;
1401
Arun Patole28eb65e2015-04-06 17:29:48 +05301402 case EOpExp:
1403 if (!foldFloatTypeUnary(unionArray[i], &expf, infoSink, &tempConstArray[i]))
1404 return nullptr;
1405 break;
1406
1407 case EOpLog:
1408 // For log(x), results are undefined if x <= 0, we are choosing to set result to 0.
1409 if (getType().getBasicType() == EbtFloat && unionArray[i].getFConst() <= 0.0f)
1410 tempConstArray[i].setFConst(0.0f);
1411 else if (!foldFloatTypeUnary(unionArray[i], &logf, infoSink, &tempConstArray[i]))
1412 return nullptr;
1413 break;
1414
1415 case EOpExp2:
1416 if (!foldFloatTypeUnary(unionArray[i], &exp2f, infoSink, &tempConstArray[i]))
1417 return nullptr;
1418 break;
1419
1420 case EOpLog2:
1421 // For log2(x), results are undefined if x <= 0, we are choosing to set result to 0.
1422 // And log2f is not available on some plarforms like old android, so just using log(x)/log(2) here.
1423 if (getType().getBasicType() == EbtFloat && unionArray[i].getFConst() <= 0.0f)
1424 tempConstArray[i].setFConst(0.0f);
1425 else if (!foldFloatTypeUnary(unionArray[i], &logf, infoSink, &tempConstArray[i]))
1426 return nullptr;
1427 else
1428 tempConstArray[i].setFConst(tempConstArray[i].getFConst() / logf(2.0f));
1429 break;
1430
1431 case EOpSqrt:
1432 // For sqrt(x), results are undefined if x < 0, we are choosing to set result to 0.
1433 if (getType().getBasicType() == EbtFloat && unionArray[i].getFConst() < 0.0f)
1434 tempConstArray[i].setFConst(0.0f);
1435 else if (!foldFloatTypeUnary(unionArray[i], &sqrtf, infoSink, &tempConstArray[i]))
1436 return nullptr;
1437 break;
1438
1439 case EOpInverseSqrt:
1440 // There is no stdlib built-in function equavalent for GLES built-in inversesqrt(),
1441 // so getting the square root first using builtin function sqrt() and then taking its inverse.
1442 // Also, for inversesqrt(x), results are undefined if x <= 0, we are choosing to set result to 0.
1443 if (getType().getBasicType() == EbtFloat && unionArray[i].getFConst() <= 0.0f)
1444 tempConstArray[i].setFConst(0.0f);
1445 else if (!foldFloatTypeUnary(unionArray[i], &sqrtf, infoSink, &tempConstArray[i]))
1446 return nullptr;
1447 else
1448 tempConstArray[i].setFConst(1.0f / tempConstArray[i].getFConst());
1449 break;
1450
Jamie Madillb1a85f42014-08-19 15:23:24 -04001451 default:
Arun Patolefddc2112015-04-22 13:28:10 +05301452 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001453 }
1454 }
1455 newNode = new TIntermConstantUnion(tempConstArray, getType());
1456 newNode->setLine(getLine());
1457 return newNode;
1458 }
1459}
1460
Arun Patole9dea48f2015-04-02 11:45:09 +05301461bool TIntermConstantUnion::foldFloatTypeUnary(const ConstantUnion &parameter, FloatTypeUnaryFunc builtinFunc,
1462 TInfoSink &infoSink, ConstantUnion *result) const
1463{
1464 ASSERT(builtinFunc);
1465
1466 if (getType().getBasicType() == EbtFloat)
1467 {
1468 result->setFConst(builtinFunc(parameter.getFConst()));
1469 return true;
1470 }
1471
1472 infoSink.info.message(
1473 EPrefixInternalError, getLine(),
1474 "Unary operation not folded into constant");
1475 return false;
1476}
1477
Jamie Madillb1a85f42014-08-19 15:23:24 -04001478// static
1479TString TIntermTraverser::hash(const TString &name, ShHashFunction64 hashFunction)
1480{
1481 if (hashFunction == NULL || name.empty())
1482 return name;
1483 khronos_uint64_t number = (*hashFunction)(name.c_str(), name.length());
1484 TStringStream stream;
1485 stream << HASHED_NAME_PREFIX << std::hex << number;
1486 TString hashedName = stream.str();
1487 return hashedName;
1488}
Olli Etuaho853dc1a2014-11-06 17:25:48 +02001489
1490void TIntermTraverser::updateTree()
1491{
1492 for (size_t ii = 0; ii < mReplacements.size(); ++ii)
1493 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03001494 const NodeUpdateEntry &replacement = mReplacements[ii];
1495 ASSERT(replacement.parent);
1496 bool replaced = replacement.parent->replaceChildNode(
1497 replacement.original, replacement.replacement);
Olli Etuaho853dc1a2014-11-06 17:25:48 +02001498 ASSERT(replaced);
1499
Olli Etuahocd94ef92015-04-16 19:18:10 +03001500 if (!replacement.originalBecomesChildOfReplacement)
Olli Etuaho853dc1a2014-11-06 17:25:48 +02001501 {
1502 // In AST traversing, a parent is visited before its children.
Olli Etuahocd94ef92015-04-16 19:18:10 +03001503 // After we replace a node, if its immediate child is to
Olli Etuaho853dc1a2014-11-06 17:25:48 +02001504 // be replaced, we need to make sure we don't update the replaced
1505 // node; instead, we update the replacement node.
1506 for (size_t jj = ii + 1; jj < mReplacements.size(); ++jj)
1507 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03001508 NodeUpdateEntry &replacement2 = mReplacements[jj];
1509 if (replacement2.parent == replacement.original)
1510 replacement2.parent = replacement.replacement;
Olli Etuaho853dc1a2014-11-06 17:25:48 +02001511 }
1512 }
1513 }
Olli Etuahofc0e2bc2015-04-16 13:39:56 +03001514 for (size_t ii = 0; ii < mMultiReplacements.size(); ++ii)
1515 {
1516 const NodeReplaceWithMultipleEntry &replacement = mMultiReplacements[ii];
1517 ASSERT(replacement.parent);
1518 bool replaced = replacement.parent->replaceChildNodeWithMultiple(
1519 replacement.original, replacement.replacements);
1520 ASSERT(replaced);
1521 }
Olli Etuaho853dc1a2014-11-06 17:25:48 +02001522}