blob: b339798404a336e6f8a20187b2c1e7a83db1d505 [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,
Jamie Madillb11e2482015-05-04 14:21:22 -040067 const TConstantUnion *rightUnionArray,
68 const TConstantUnion *leftUnionArray);
Jamie Madillb1a85f42014-08-19 15:23:24 -040069
70bool CompareStruct(const TType &leftNodeType,
Jamie Madillb11e2482015-05-04 14:21:22 -040071 const TConstantUnion *rightUnionArray,
72 const TConstantUnion *leftUnionArray)
Jamie Madillb1a85f42014-08-19 15:23:24 -040073{
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,
Jamie Madillb11e2482015-05-04 14:21:22 -0400105 const TConstantUnion *rightUnionArray,
106 const TConstantUnion *leftUnionArray)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400107{
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);
Olli Etuaho8fee0ab2015-04-23 14:52:46 +0300205 mSequence.insert(it, replacements.begin(), replacements.end());
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300206 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(
Olli Etuaho2cb7b832015-04-23 20:27:44 +0300669 TOperator op, TIntermConstantUnion *rightNode, TInfoSink &infoSink)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400670{
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400671 TConstantUnion *unionArray = getUnionArrayPointer();
Jamie Madillb1a85f42014-08-19 15:23:24 -0400672
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
Olli Etuaho2cb7b832015-04-23 20:27:44 +0300678 if (rightNode)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400679 {
680 // binary operations
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400681 TConstantUnion *rightUnionArray = rightNode->getUnionArrayPointer();
Jamie Madillb1a85f42014-08-19 15:23:24 -0400682 TType returnType = getType();
683
684 if (!rightUnionArray)
Arun Patolefddc2112015-04-22 13:28:10 +0530685 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400686
Olli Etuaho2cb7b832015-04-23 20:27:44 +0300687 // for a case like float f = vec4(2, 3, 4, 5) + 1.2;
688 if (rightNode->getType().getObjectSize() == 1 && objectSize > 1)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400689 {
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400690 rightUnionArray = new TConstantUnion[objectSize];
Jamie Madillb1a85f42014-08-19 15:23:24 -0400691 for (size_t i = 0; i < objectSize; ++i)
692 {
Olli Etuaho2cb7b832015-04-23 20:27:44 +0300693 rightUnionArray[i] = *rightNode->getUnionArrayPointer();
Jamie Madillb1a85f42014-08-19 15:23:24 -0400694 }
695 returnType = getType();
696 }
Olli Etuaho2cb7b832015-04-23 20:27:44 +0300697 else if (rightNode->getType().getObjectSize() > 1 && objectSize == 1)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400698 {
Olli Etuaho2cb7b832015-04-23 20:27:44 +0300699 // for a case like float f = 1.2 + vec4(2, 3, 4, 5);
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400700 unionArray = new TConstantUnion[rightNode->getType().getObjectSize()];
Olli Etuaho2cb7b832015-04-23 20:27:44 +0300701 for (size_t i = 0; i < rightNode->getType().getObjectSize(); ++i)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400702 {
703 unionArray[i] = *getUnionArrayPointer();
704 }
Olli Etuaho2cb7b832015-04-23 20:27:44 +0300705 returnType = rightNode->getType();
706 objectSize = rightNode->getType().getObjectSize();
Jamie Madillb1a85f42014-08-19 15:23:24 -0400707 }
708
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400709 TConstantUnion *tempConstArray = nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400710 TIntermConstantUnion *tempNode;
711
712 bool boolNodeFlag = false;
713 switch(op)
714 {
715 case EOpAdd:
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400716 tempConstArray = new TConstantUnion[objectSize];
Jamie Madillb1a85f42014-08-19 15:23:24 -0400717 for (size_t i = 0; i < objectSize; i++)
718 tempConstArray[i] = unionArray[i] + rightUnionArray[i];
719 break;
720 case EOpSub:
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400721 tempConstArray = new TConstantUnion[objectSize];
Jamie Madillb1a85f42014-08-19 15:23:24 -0400722 for (size_t i = 0; i < objectSize; i++)
723 tempConstArray[i] = unionArray[i] - rightUnionArray[i];
724 break;
725
726 case EOpMul:
727 case EOpVectorTimesScalar:
728 case EOpMatrixTimesScalar:
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400729 tempConstArray = new TConstantUnion[objectSize];
Jamie Madillb1a85f42014-08-19 15:23:24 -0400730 for (size_t i = 0; i < objectSize; i++)
731 tempConstArray[i] = unionArray[i] * rightUnionArray[i];
732 break;
733
734 case EOpMatrixTimesMatrix:
735 {
736 if (getType().getBasicType() != EbtFloat ||
Olli Etuaho2cb7b832015-04-23 20:27:44 +0300737 rightNode->getBasicType() != EbtFloat)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400738 {
739 infoSink.info.message(
740 EPrefixInternalError, getLine(),
741 "Constant Folding cannot be done for matrix multiply");
Arun Patolefddc2112015-04-22 13:28:10 +0530742 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400743 }
744
745 const int leftCols = getCols();
746 const int leftRows = getRows();
Olli Etuaho2cb7b832015-04-23 20:27:44 +0300747 const int rightCols = rightNode->getType().getCols();
748 const int rightRows = rightNode->getType().getRows();
Jamie Madillb1a85f42014-08-19 15:23:24 -0400749 const int resultCols = rightCols;
750 const int resultRows = leftRows;
751
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400752 tempConstArray = new TConstantUnion[resultCols * resultRows];
Jamie Madillb1a85f42014-08-19 15:23:24 -0400753 for (int row = 0; row < resultRows; row++)
754 {
755 for (int column = 0; column < resultCols; column++)
756 {
757 tempConstArray[resultRows * column + row].setFConst(0.0f);
758 for (int i = 0; i < leftCols; i++)
759 {
760 tempConstArray[resultRows * column + row].setFConst(
761 tempConstArray[resultRows * column + row].getFConst() +
762 unionArray[i * leftRows + row].getFConst() *
763 rightUnionArray[column * rightRows + i].getFConst());
764 }
765 }
766 }
767
768 // update return type for matrix product
Minmin Gong794e0002015-04-07 18:31:54 -0700769 returnType.setPrimarySize(static_cast<unsigned char>(resultCols));
770 returnType.setSecondarySize(static_cast<unsigned char>(resultRows));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400771 }
772 break;
773
774 case EOpDiv:
Olli Etuahoff805cc2015-02-13 10:59:34 +0200775 case EOpIMod:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400776 {
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400777 tempConstArray = new TConstantUnion[objectSize];
Jamie Madillb1a85f42014-08-19 15:23:24 -0400778 for (size_t i = 0; i < objectSize; i++)
779 {
780 switch (getType().getBasicType())
781 {
782 case EbtFloat:
783 if (rightUnionArray[i] == 0.0f)
784 {
785 infoSink.info.message(
786 EPrefixWarning, getLine(),
787 "Divide by zero error during constant folding");
788 tempConstArray[i].setFConst(
789 unionArray[i].getFConst() < 0 ? -FLT_MAX : FLT_MAX);
790 }
791 else
792 {
Olli Etuaho3eab00a2015-02-12 16:02:39 +0200793 ASSERT(op == EOpDiv);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400794 tempConstArray[i].setFConst(
795 unionArray[i].getFConst() /
796 rightUnionArray[i].getFConst());
797 }
798 break;
799
800 case EbtInt:
801 if (rightUnionArray[i] == 0)
802 {
803 infoSink.info.message(
804 EPrefixWarning, getLine(),
805 "Divide by zero error during constant folding");
806 tempConstArray[i].setIConst(INT_MAX);
807 }
808 else
809 {
Olli Etuaho3eab00a2015-02-12 16:02:39 +0200810 if (op == EOpDiv)
811 {
812 tempConstArray[i].setIConst(
813 unionArray[i].getIConst() /
814 rightUnionArray[i].getIConst());
815 }
816 else
817 {
818 ASSERT(op == EOpIMod);
819 tempConstArray[i].setIConst(
820 unionArray[i].getIConst() %
821 rightUnionArray[i].getIConst());
822 }
Jamie Madillb1a85f42014-08-19 15:23:24 -0400823 }
824 break;
825
826 case EbtUInt:
827 if (rightUnionArray[i] == 0)
828 {
829 infoSink.info.message(
830 EPrefixWarning, getLine(),
831 "Divide by zero error during constant folding");
832 tempConstArray[i].setUConst(UINT_MAX);
833 }
834 else
835 {
Olli Etuaho3eab00a2015-02-12 16:02:39 +0200836 if (op == EOpDiv)
837 {
838 tempConstArray[i].setUConst(
839 unionArray[i].getUConst() /
840 rightUnionArray[i].getUConst());
841 }
842 else
843 {
844 ASSERT(op == EOpIMod);
845 tempConstArray[i].setUConst(
846 unionArray[i].getUConst() %
847 rightUnionArray[i].getUConst());
848 }
Jamie Madillb1a85f42014-08-19 15:23:24 -0400849 }
850 break;
851
852 default:
853 infoSink.info.message(
854 EPrefixInternalError, getLine(),
855 "Constant folding cannot be done for \"/\"");
Arun Patolefddc2112015-04-22 13:28:10 +0530856 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400857 }
858 }
859 }
860 break;
861
862 case EOpMatrixTimesVector:
863 {
Olli Etuaho2cb7b832015-04-23 20:27:44 +0300864 if (rightNode->getBasicType() != EbtFloat)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400865 {
866 infoSink.info.message(
867 EPrefixInternalError, getLine(),
868 "Constant Folding cannot be done for matrix times vector");
Arun Patolefddc2112015-04-22 13:28:10 +0530869 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400870 }
871
872 const int matrixCols = getCols();
873 const int matrixRows = getRows();
874
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400875 tempConstArray = new TConstantUnion[matrixRows];
Jamie Madillb1a85f42014-08-19 15:23:24 -0400876
877 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
878 {
879 tempConstArray[matrixRow].setFConst(0.0f);
880 for (int col = 0; col < matrixCols; col++)
881 {
882 tempConstArray[matrixRow].setFConst(
883 tempConstArray[matrixRow].getFConst() +
884 unionArray[col * matrixRows + matrixRow].getFConst() *
885 rightUnionArray[col].getFConst());
886 }
887 }
888
Olli Etuaho2cb7b832015-04-23 20:27:44 +0300889 returnType = rightNode->getType();
Minmin Gong794e0002015-04-07 18:31:54 -0700890 returnType.setPrimarySize(static_cast<unsigned char>(matrixRows));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400891
892 tempNode = new TIntermConstantUnion(tempConstArray, returnType);
893 tempNode->setLine(getLine());
894
895 return tempNode;
896 }
897
898 case EOpVectorTimesMatrix:
899 {
900 if (getType().getBasicType() != EbtFloat)
901 {
902 infoSink.info.message(
903 EPrefixInternalError, getLine(),
904 "Constant Folding cannot be done for vector times matrix");
Arun Patolefddc2112015-04-22 13:28:10 +0530905 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400906 }
907
Olli Etuaho2cb7b832015-04-23 20:27:44 +0300908 const int matrixCols = rightNode->getType().getCols();
909 const int matrixRows = rightNode->getType().getRows();
Jamie Madillb1a85f42014-08-19 15:23:24 -0400910
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400911 tempConstArray = new TConstantUnion[matrixCols];
Jamie Madillb1a85f42014-08-19 15:23:24 -0400912
913 for (int matrixCol = 0; matrixCol < matrixCols; matrixCol++)
914 {
915 tempConstArray[matrixCol].setFConst(0.0f);
916 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
917 {
918 tempConstArray[matrixCol].setFConst(
919 tempConstArray[matrixCol].getFConst() +
920 unionArray[matrixRow].getFConst() *
921 rightUnionArray[matrixCol * matrixRows + matrixRow].getFConst());
922 }
923 }
924
Minmin Gong794e0002015-04-07 18:31:54 -0700925 returnType.setPrimarySize(static_cast<unsigned char>(matrixCols));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400926 }
927 break;
928
929 case EOpLogicalAnd:
930 // this code is written for possible future use,
931 // will not get executed currently
932 {
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400933 tempConstArray = new TConstantUnion[objectSize];
Jamie Madillb1a85f42014-08-19 15:23:24 -0400934 for (size_t i = 0; i < objectSize; i++)
935 {
936 tempConstArray[i] = unionArray[i] && rightUnionArray[i];
937 }
938 }
939 break;
940
941 case EOpLogicalOr:
942 // this code is written for possible future use,
943 // will not get executed currently
944 {
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400945 tempConstArray = new TConstantUnion[objectSize];
Jamie Madillb1a85f42014-08-19 15:23:24 -0400946 for (size_t i = 0; i < objectSize; i++)
947 {
948 tempConstArray[i] = unionArray[i] || rightUnionArray[i];
949 }
950 }
951 break;
952
953 case EOpLogicalXor:
954 {
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400955 tempConstArray = new TConstantUnion[objectSize];
Jamie Madillb1a85f42014-08-19 15:23:24 -0400956 for (size_t i = 0; i < objectSize; i++)
957 {
958 switch (getType().getBasicType())
959 {
960 case EbtBool:
961 tempConstArray[i].setBConst(
962 unionArray[i] == rightUnionArray[i] ? false : true);
963 break;
964 default:
965 UNREACHABLE();
966 break;
967 }
968 }
969 }
970 break;
971
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200972 case EOpBitwiseAnd:
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400973 tempConstArray = new TConstantUnion[objectSize];
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200974 for (size_t i = 0; i < objectSize; i++)
975 tempConstArray[i] = unionArray[i] & rightUnionArray[i];
976 break;
977 case EOpBitwiseXor:
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400978 tempConstArray = new TConstantUnion[objectSize];
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200979 for (size_t i = 0; i < objectSize; i++)
980 tempConstArray[i] = unionArray[i] ^ rightUnionArray[i];
981 break;
982 case EOpBitwiseOr:
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400983 tempConstArray = new TConstantUnion[objectSize];
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200984 for (size_t i = 0; i < objectSize; i++)
985 tempConstArray[i] = unionArray[i] | rightUnionArray[i];
986 break;
987 case EOpBitShiftLeft:
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400988 tempConstArray = new TConstantUnion[objectSize];
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200989 for (size_t i = 0; i < objectSize; i++)
990 tempConstArray[i] = unionArray[i] << rightUnionArray[i];
991 break;
992 case EOpBitShiftRight:
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400993 tempConstArray = new TConstantUnion[objectSize];
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200994 for (size_t i = 0; i < objectSize; i++)
995 tempConstArray[i] = unionArray[i] >> rightUnionArray[i];
996 break;
997
Jamie Madillb1a85f42014-08-19 15:23:24 -0400998 case EOpLessThan:
999 ASSERT(objectSize == 1);
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001000 tempConstArray = new TConstantUnion[1];
Jamie Madillb1a85f42014-08-19 15:23:24 -04001001 tempConstArray->setBConst(*unionArray < *rightUnionArray);
1002 returnType = TType(EbtBool, EbpUndefined, EvqConst);
1003 break;
1004
1005 case EOpGreaterThan:
1006 ASSERT(objectSize == 1);
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001007 tempConstArray = new TConstantUnion[1];
Jamie Madillb1a85f42014-08-19 15:23:24 -04001008 tempConstArray->setBConst(*unionArray > *rightUnionArray);
1009 returnType = TType(EbtBool, EbpUndefined, EvqConst);
1010 break;
1011
1012 case EOpLessThanEqual:
1013 {
1014 ASSERT(objectSize == 1);
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001015 TConstantUnion constant;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001016 constant.setBConst(*unionArray > *rightUnionArray);
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001017 tempConstArray = new TConstantUnion[1];
Jamie Madillb1a85f42014-08-19 15:23:24 -04001018 tempConstArray->setBConst(!constant.getBConst());
1019 returnType = TType(EbtBool, EbpUndefined, EvqConst);
1020 break;
1021 }
1022
1023 case EOpGreaterThanEqual:
1024 {
1025 ASSERT(objectSize == 1);
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001026 TConstantUnion constant;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001027 constant.setBConst(*unionArray < *rightUnionArray);
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001028 tempConstArray = new TConstantUnion[1];
Jamie Madillb1a85f42014-08-19 15:23:24 -04001029 tempConstArray->setBConst(!constant.getBConst());
1030 returnType = TType(EbtBool, EbpUndefined, EvqConst);
1031 break;
1032 }
1033
1034 case EOpEqual:
1035 if (getType().getBasicType() == EbtStruct)
1036 {
Olli Etuaho2cb7b832015-04-23 20:27:44 +03001037 if (!CompareStructure(rightNode->getType(),
1038 rightNode->getUnionArrayPointer(),
Jamie Madillb1a85f42014-08-19 15:23:24 -04001039 unionArray))
1040 {
1041 boolNodeFlag = true;
1042 }
1043 }
1044 else
1045 {
1046 for (size_t i = 0; i < objectSize; i++)
1047 {
1048 if (unionArray[i] != rightUnionArray[i])
1049 {
1050 boolNodeFlag = true;
1051 break; // break out of for loop
1052 }
1053 }
1054 }
1055
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001056 tempConstArray = new TConstantUnion[1];
Jamie Madillb1a85f42014-08-19 15:23:24 -04001057 if (!boolNodeFlag)
1058 {
1059 tempConstArray->setBConst(true);
1060 }
1061 else
1062 {
1063 tempConstArray->setBConst(false);
1064 }
1065
1066 tempNode = new TIntermConstantUnion(
1067 tempConstArray, TType(EbtBool, EbpUndefined, EvqConst));
1068 tempNode->setLine(getLine());
1069
1070 return tempNode;
1071
1072 case EOpNotEqual:
1073 if (getType().getBasicType() == EbtStruct)
1074 {
Olli Etuaho2cb7b832015-04-23 20:27:44 +03001075 if (CompareStructure(rightNode->getType(),
1076 rightNode->getUnionArrayPointer(),
Jamie Madillb1a85f42014-08-19 15:23:24 -04001077 unionArray))
1078 {
1079 boolNodeFlag = true;
1080 }
1081 }
1082 else
1083 {
1084 for (size_t i = 0; i < objectSize; i++)
1085 {
1086 if (unionArray[i] == rightUnionArray[i])
1087 {
1088 boolNodeFlag = true;
1089 break; // break out of for loop
1090 }
1091 }
1092 }
1093
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001094 tempConstArray = new TConstantUnion[1];
Jamie Madillb1a85f42014-08-19 15:23:24 -04001095 if (!boolNodeFlag)
1096 {
1097 tempConstArray->setBConst(true);
1098 }
1099 else
1100 {
1101 tempConstArray->setBConst(false);
1102 }
1103
1104 tempNode = new TIntermConstantUnion(
1105 tempConstArray, TType(EbtBool, EbpUndefined, EvqConst));
1106 tempNode->setLine(getLine());
1107
1108 return tempNode;
1109
1110 default:
1111 infoSink.info.message(
1112 EPrefixInternalError, getLine(),
1113 "Invalid operator for constant folding");
Arun Patolefddc2112015-04-22 13:28:10 +05301114 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001115 }
1116 tempNode = new TIntermConstantUnion(tempConstArray, returnType);
1117 tempNode->setLine(getLine());
1118
1119 return tempNode;
1120 }
1121 else
1122 {
1123 //
1124 // Do unary operations
1125 //
1126 TIntermConstantUnion *newNode = 0;
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001127 TConstantUnion* tempConstArray = new TConstantUnion[objectSize];
Jamie Madillb1a85f42014-08-19 15:23:24 -04001128 for (size_t i = 0; i < objectSize; i++)
1129 {
1130 switch(op)
1131 {
1132 case EOpNegative:
1133 switch (getType().getBasicType())
1134 {
1135 case EbtFloat:
1136 tempConstArray[i].setFConst(-unionArray[i].getFConst());
1137 break;
1138 case EbtInt:
1139 tempConstArray[i].setIConst(-unionArray[i].getIConst());
1140 break;
1141 case EbtUInt:
1142 tempConstArray[i].setUConst(static_cast<unsigned int>(
1143 -static_cast<int>(unionArray[i].getUConst())));
1144 break;
1145 default:
1146 infoSink.info.message(
1147 EPrefixInternalError, getLine(),
1148 "Unary operation not folded into constant");
Arun Patolefddc2112015-04-22 13:28:10 +05301149 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001150 }
1151 break;
1152
Zhenyao Mode1e00e2014-10-09 16:55:32 -07001153 case EOpPositive:
1154 switch (getType().getBasicType())
1155 {
1156 case EbtFloat:
1157 tempConstArray[i].setFConst(unionArray[i].getFConst());
1158 break;
1159 case EbtInt:
1160 tempConstArray[i].setIConst(unionArray[i].getIConst());
1161 break;
1162 case EbtUInt:
1163 tempConstArray[i].setUConst(static_cast<unsigned int>(
1164 static_cast<int>(unionArray[i].getUConst())));
1165 break;
1166 default:
1167 infoSink.info.message(
1168 EPrefixInternalError, getLine(),
1169 "Unary operation not folded into constant");
Arun Patolefddc2112015-04-22 13:28:10 +05301170 return nullptr;
Zhenyao Mode1e00e2014-10-09 16:55:32 -07001171 }
1172 break;
1173
Jamie Madillb1a85f42014-08-19 15:23:24 -04001174 case EOpLogicalNot:
1175 // this code is written for possible future use,
1176 // will not get executed currently
1177 switch (getType().getBasicType())
1178 {
1179 case EbtBool:
1180 tempConstArray[i].setBConst(!unionArray[i].getBConst());
1181 break;
1182 default:
1183 infoSink.info.message(
1184 EPrefixInternalError, getLine(),
1185 "Unary operation not folded into constant");
Arun Patolefddc2112015-04-22 13:28:10 +05301186 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001187 }
1188 break;
1189
Olli Etuaho31b5fc62015-01-16 12:13:36 +02001190 case EOpBitwiseNot:
1191 switch (getType().getBasicType())
1192 {
1193 case EbtInt:
1194 tempConstArray[i].setIConst(~unionArray[i].getIConst());
1195 break;
1196 case EbtUInt:
1197 tempConstArray[i].setUConst(~unionArray[i].getUConst());
1198 break;
1199 default:
1200 infoSink.info.message(
1201 EPrefixInternalError, getLine(),
1202 "Unary operation not folded into constant");
Arun Patolefddc2112015-04-22 13:28:10 +05301203 return nullptr;
Olli Etuaho31b5fc62015-01-16 12:13:36 +02001204 }
1205 break;
1206
Arun Patole9dea48f2015-04-02 11:45:09 +05301207 case EOpRadians:
1208 if (getType().getBasicType() == EbtFloat)
1209 {
1210 tempConstArray[i].setFConst(kDegreesToRadiansMultiplier * unionArray[i].getFConst());
1211 break;
1212 }
1213 infoSink.info.message(
1214 EPrefixInternalError, getLine(),
1215 "Unary operation not folded into constant");
1216 return nullptr;
1217
1218 case EOpDegrees:
1219 if (getType().getBasicType() == EbtFloat)
1220 {
1221 tempConstArray[i].setFConst(kRadiansToDegreesMultiplier * unionArray[i].getFConst());
1222 break;
1223 }
1224 infoSink.info.message(
1225 EPrefixInternalError, getLine(),
1226 "Unary operation not folded into constant");
1227 return nullptr;
1228
1229 case EOpSin:
1230 if (!foldFloatTypeUnary(unionArray[i], &sinf, infoSink, &tempConstArray[i]))
1231 return nullptr;
1232 break;
1233
1234 case EOpCos:
1235 if (!foldFloatTypeUnary(unionArray[i], &cosf, infoSink, &tempConstArray[i]))
1236 return nullptr;
1237 break;
1238
1239 case EOpTan:
1240 if (!foldFloatTypeUnary(unionArray[i], &tanf, infoSink, &tempConstArray[i]))
1241 return nullptr;
1242 break;
1243
1244 case EOpAsin:
1245 // For asin(x), results are undefined if |x| > 1, we are choosing to set result to 0.
1246 if (getType().getBasicType() == EbtFloat && fabsf(unionArray[i].getFConst()) > 1.0f)
1247 tempConstArray[i].setFConst(0.0f);
1248 else if (!foldFloatTypeUnary(unionArray[i], &asinf, infoSink, &tempConstArray[i]))
1249 return nullptr;
1250 break;
1251
1252 case EOpAcos:
1253 // For acos(x), results are undefined if |x| > 1, we are choosing to set result to 0.
1254 if (getType().getBasicType() == EbtFloat && fabsf(unionArray[i].getFConst()) > 1.0f)
1255 tempConstArray[i].setFConst(0.0f);
1256 else if (!foldFloatTypeUnary(unionArray[i], &acosf, infoSink, &tempConstArray[i]))
1257 return nullptr;
1258 break;
1259
1260 case EOpAtan:
1261 if (!foldFloatTypeUnary(unionArray[i], &atanf, infoSink, &tempConstArray[i]))
1262 return nullptr;
1263 break;
1264
1265 case EOpSinh:
1266 if (!foldFloatTypeUnary(unionArray[i], &sinhf, infoSink, &tempConstArray[i]))
1267 return nullptr;
1268 break;
1269
1270 case EOpCosh:
1271 if (!foldFloatTypeUnary(unionArray[i], &coshf, infoSink, &tempConstArray[i]))
1272 return nullptr;
1273 break;
1274
1275 case EOpTanh:
1276 if (!foldFloatTypeUnary(unionArray[i], &tanhf, infoSink, &tempConstArray[i]))
1277 return nullptr;
1278 break;
1279
1280 case EOpAsinh:
1281 if (!foldFloatTypeUnary(unionArray[i], &asinhf, infoSink, &tempConstArray[i]))
1282 return nullptr;
1283 break;
1284
1285 case EOpAcosh:
1286 // For acosh(x), results are undefined if x < 1, we are choosing to set result to 0.
1287 if (getType().getBasicType() == EbtFloat && unionArray[i].getFConst() < 1.0f)
1288 tempConstArray[i].setFConst(0.0f);
1289 else if (!foldFloatTypeUnary(unionArray[i], &acoshf, infoSink, &tempConstArray[i]))
1290 return nullptr;
1291 break;
1292
1293 case EOpAtanh:
1294 // For atanh(x), results are undefined if |x| >= 1, we are choosing to set result to 0.
1295 if (getType().getBasicType() == EbtFloat && fabsf(unionArray[i].getFConst()) >= 1.0f)
1296 tempConstArray[i].setFConst(0.0f);
1297 else if (!foldFloatTypeUnary(unionArray[i], &atanhf, infoSink, &tempConstArray[i]))
1298 return nullptr;
1299 break;
1300
Arun Patole97dc22e2015-04-06 17:35:38 +05301301 case EOpAbs:
1302 switch (getType().getBasicType())
1303 {
1304 case EbtFloat:
1305 tempConstArray[i].setFConst(fabsf(unionArray[i].getFConst()));
1306 break;
1307 case EbtInt:
1308 tempConstArray[i].setIConst(abs(unionArray[i].getIConst()));
1309 break;
1310 default:
1311 infoSink.info.message(
1312 EPrefixInternalError, getLine(),
1313 "Unary operation not folded into constant");
1314 return nullptr;
1315 }
1316 break;
1317
1318 case EOpSign:
1319 switch (getType().getBasicType())
1320 {
1321 case EbtFloat:
1322 {
1323 float fConst = unionArray[i].getFConst();
1324 float fResult = 0.0f;
1325 if (fConst > 0.0f)
1326 fResult = 1.0f;
1327 else if (fConst < 0.0f)
1328 fResult = -1.0f;
1329 tempConstArray[i].setFConst(fResult);
1330 }
1331 break;
1332 case EbtInt:
1333 {
1334 int iConst = unionArray[i].getIConst();
1335 int iResult = 0;
1336 if (iConst > 0)
1337 iResult = 1;
1338 else if (iConst < 0)
1339 iResult = -1;
1340 tempConstArray[i].setIConst(iResult);
1341 }
1342 break;
1343 default:
1344 infoSink.info.message(
1345 EPrefixInternalError, getLine(),
1346 "Unary operation not folded into constant");
1347 return nullptr;
1348 }
1349 break;
1350
1351 case EOpFloor:
1352 if (!foldFloatTypeUnary(unionArray[i], &floorf, infoSink, &tempConstArray[i]))
1353 return nullptr;
1354 break;
1355
1356 case EOpTrunc:
1357 if (!foldFloatTypeUnary(unionArray[i], &truncf, infoSink, &tempConstArray[i]))
1358 return nullptr;
1359 break;
1360
1361 case EOpRound:
1362 if (!foldFloatTypeUnary(unionArray[i], &roundf, infoSink, &tempConstArray[i]))
1363 return nullptr;
1364 break;
1365
1366 case EOpRoundEven:
1367 if (getType().getBasicType() == EbtFloat)
1368 {
1369 float x = unionArray[i].getFConst();
1370 float result;
1371 float fractPart = modff(x, &result);
1372 if (fabsf(fractPart) == 0.5f)
1373 result = 2.0f * roundf(x / 2.0f);
1374 else
1375 result = roundf(x);
1376 tempConstArray[i].setFConst(result);
1377 break;
1378 }
1379 infoSink.info.message(
1380 EPrefixInternalError, getLine(),
1381 "Unary operation not folded into constant");
1382 return nullptr;
1383
1384 case EOpCeil:
1385 if (!foldFloatTypeUnary(unionArray[i], &ceilf, infoSink, &tempConstArray[i]))
1386 return nullptr;
1387 break;
1388
1389 case EOpFract:
1390 if (getType().getBasicType() == EbtFloat)
1391 {
1392 float x = unionArray[i].getFConst();
1393 tempConstArray[i].setFConst(x - floorf(x));
1394 break;
1395 }
1396 infoSink.info.message(
1397 EPrefixInternalError, getLine(),
1398 "Unary operation not folded into constant");
1399 return nullptr;
1400
Arun Patole28eb65e2015-04-06 17:29:48 +05301401 case EOpExp:
1402 if (!foldFloatTypeUnary(unionArray[i], &expf, infoSink, &tempConstArray[i]))
1403 return nullptr;
1404 break;
1405
1406 case EOpLog:
1407 // For log(x), results are undefined if x <= 0, we are choosing to set result to 0.
1408 if (getType().getBasicType() == EbtFloat && unionArray[i].getFConst() <= 0.0f)
1409 tempConstArray[i].setFConst(0.0f);
1410 else if (!foldFloatTypeUnary(unionArray[i], &logf, infoSink, &tempConstArray[i]))
1411 return nullptr;
1412 break;
1413
1414 case EOpExp2:
1415 if (!foldFloatTypeUnary(unionArray[i], &exp2f, infoSink, &tempConstArray[i]))
1416 return nullptr;
1417 break;
1418
1419 case EOpLog2:
1420 // For log2(x), results are undefined if x <= 0, we are choosing to set result to 0.
1421 // And log2f is not available on some plarforms like old android, so just using log(x)/log(2) here.
1422 if (getType().getBasicType() == EbtFloat && unionArray[i].getFConst() <= 0.0f)
1423 tempConstArray[i].setFConst(0.0f);
1424 else if (!foldFloatTypeUnary(unionArray[i], &logf, infoSink, &tempConstArray[i]))
1425 return nullptr;
1426 else
1427 tempConstArray[i].setFConst(tempConstArray[i].getFConst() / logf(2.0f));
1428 break;
1429
1430 case EOpSqrt:
1431 // For sqrt(x), results are undefined if x < 0, we are choosing to set result to 0.
1432 if (getType().getBasicType() == EbtFloat && unionArray[i].getFConst() < 0.0f)
1433 tempConstArray[i].setFConst(0.0f);
1434 else if (!foldFloatTypeUnary(unionArray[i], &sqrtf, infoSink, &tempConstArray[i]))
1435 return nullptr;
1436 break;
1437
1438 case EOpInverseSqrt:
1439 // There is no stdlib built-in function equavalent for GLES built-in inversesqrt(),
1440 // so getting the square root first using builtin function sqrt() and then taking its inverse.
1441 // Also, for inversesqrt(x), results are undefined if x <= 0, we are choosing to set result to 0.
1442 if (getType().getBasicType() == EbtFloat && unionArray[i].getFConst() <= 0.0f)
1443 tempConstArray[i].setFConst(0.0f);
1444 else if (!foldFloatTypeUnary(unionArray[i], &sqrtf, infoSink, &tempConstArray[i]))
1445 return nullptr;
1446 else
1447 tempConstArray[i].setFConst(1.0f / tempConstArray[i].getFConst());
1448 break;
1449
Jamie Madillb1a85f42014-08-19 15:23:24 -04001450 default:
Arun Patolefddc2112015-04-22 13:28:10 +05301451 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001452 }
1453 }
1454 newNode = new TIntermConstantUnion(tempConstArray, getType());
1455 newNode->setLine(getLine());
1456 return newNode;
1457 }
1458}
1459
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001460bool TIntermConstantUnion::foldFloatTypeUnary(const TConstantUnion &parameter, FloatTypeUnaryFunc builtinFunc,
1461 TInfoSink &infoSink, TConstantUnion *result) const
Arun Patole9dea48f2015-04-02 11:45:09 +05301462{
1463 ASSERT(builtinFunc);
1464
1465 if (getType().getBasicType() == EbtFloat)
1466 {
1467 result->setFConst(builtinFunc(parameter.getFConst()));
1468 return true;
1469 }
1470
1471 infoSink.info.message(
1472 EPrefixInternalError, getLine(),
1473 "Unary operation not folded into constant");
1474 return false;
1475}
1476
Jamie Madillb1a85f42014-08-19 15:23:24 -04001477// static
1478TString TIntermTraverser::hash(const TString &name, ShHashFunction64 hashFunction)
1479{
1480 if (hashFunction == NULL || name.empty())
1481 return name;
1482 khronos_uint64_t number = (*hashFunction)(name.c_str(), name.length());
1483 TStringStream stream;
1484 stream << HASHED_NAME_PREFIX << std::hex << number;
1485 TString hashedName = stream.str();
1486 return hashedName;
1487}
Olli Etuaho853dc1a2014-11-06 17:25:48 +02001488
1489void TIntermTraverser::updateTree()
1490{
1491 for (size_t ii = 0; ii < mReplacements.size(); ++ii)
1492 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03001493 const NodeUpdateEntry &replacement = mReplacements[ii];
1494 ASSERT(replacement.parent);
1495 bool replaced = replacement.parent->replaceChildNode(
1496 replacement.original, replacement.replacement);
Olli Etuaho853dc1a2014-11-06 17:25:48 +02001497 ASSERT(replaced);
Olli Etuahod57e0db2015-04-24 15:05:08 +03001498 UNUSED_ASSERTION_VARIABLE(replaced);
Olli Etuaho853dc1a2014-11-06 17:25:48 +02001499
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);
Olli Etuahod57e0db2015-04-24 15:05:08 +03001521 UNUSED_ASSERTION_VARIABLE(replaced);
Olli Etuahofc0e2bc2015-04-16 13:39:56 +03001522 }
Olli Etuaho853dc1a2014-11-06 17:25:48 +02001523}