blob: 4b35fef64ce2f2ebfe0828c6bcc42c77ece4b1f5 [file] [log] [blame]
Jamie Madillb1a85f42014-08-19 15:23:24 -04001//
2// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved.
3// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7//
8// Build the intermediate representation.
9//
10
11#include <float.h>
12#include <limits.h>
Arun Patole9dea48f2015-04-02 11:45:09 +053013#include <math.h>
Arun Patole97dc22e2015-04-06 17:35:38 +053014#include <stdlib.h>
Jamie Madillb1a85f42014-08-19 15:23:24 -040015#include <algorithm>
Arun Patole274f0702015-05-05 13:33:30 +053016#include <vector>
Jamie Madillb1a85f42014-08-19 15:23:24 -040017
Arun Patole274f0702015-05-05 13:33:30 +053018#include "common/mathutil.h"
Jamie Madillb1a85f42014-08-19 15:23:24 -040019#include "compiler/translator/HashNames.h"
20#include "compiler/translator/IntermNode.h"
21#include "compiler/translator/SymbolTable.h"
22
23namespace
24{
25
Arun Patole9dea48f2015-04-02 11:45:09 +053026const float kPi = 3.14159265358979323846f;
27const float kDegreesToRadiansMultiplier = kPi / 180.0f;
28const float kRadiansToDegreesMultiplier = 180.0f / kPi;
29
Jamie Madillb1a85f42014-08-19 15:23:24 -040030TPrecision GetHigherPrecision(TPrecision left, TPrecision right)
31{
32 return left > right ? left : right;
33}
34
35bool ValidateMultiplication(TOperator op, const TType &left, const TType &right)
36{
37 switch (op)
38 {
39 case EOpMul:
40 case EOpMulAssign:
41 return left.getNominalSize() == right.getNominalSize() &&
42 left.getSecondarySize() == right.getSecondarySize();
43 case EOpVectorTimesScalar:
44 case EOpVectorTimesScalarAssign:
45 return true;
46 case EOpVectorTimesMatrix:
47 return left.getNominalSize() == right.getRows();
48 case EOpVectorTimesMatrixAssign:
49 return left.getNominalSize() == right.getRows() &&
50 left.getNominalSize() == right.getCols();
51 case EOpMatrixTimesVector:
52 return left.getCols() == right.getNominalSize();
53 case EOpMatrixTimesScalar:
54 case EOpMatrixTimesScalarAssign:
55 return true;
56 case EOpMatrixTimesMatrix:
57 return left.getCols() == right.getRows();
58 case EOpMatrixTimesMatrixAssign:
59 return left.getCols() == right.getCols() &&
60 left.getRows() == right.getRows();
61
62 default:
63 UNREACHABLE();
64 return false;
65 }
66}
67
68bool CompareStructure(const TType& leftNodeType,
Jamie Madillb11e2482015-05-04 14:21:22 -040069 const TConstantUnion *rightUnionArray,
70 const TConstantUnion *leftUnionArray);
Jamie Madillb1a85f42014-08-19 15:23:24 -040071
72bool CompareStruct(const TType &leftNodeType,
Jamie Madillb11e2482015-05-04 14:21:22 -040073 const TConstantUnion *rightUnionArray,
74 const TConstantUnion *leftUnionArray)
Jamie Madillb1a85f42014-08-19 15:23:24 -040075{
76 const TFieldList &fields = leftNodeType.getStruct()->fields();
77
78 size_t structSize = fields.size();
79 size_t index = 0;
80
81 for (size_t j = 0; j < structSize; j++)
82 {
83 size_t size = fields[j]->type()->getObjectSize();
84 for (size_t i = 0; i < size; i++)
85 {
86 if (fields[j]->type()->getBasicType() == EbtStruct)
87 {
88 if (!CompareStructure(*fields[j]->type(),
89 &rightUnionArray[index],
90 &leftUnionArray[index]))
91 {
92 return false;
93 }
94 }
95 else
96 {
97 if (leftUnionArray[index] != rightUnionArray[index])
98 return false;
99 index++;
100 }
101 }
102 }
103 return true;
104}
105
106bool CompareStructure(const TType &leftNodeType,
Jamie Madillb11e2482015-05-04 14:21:22 -0400107 const TConstantUnion *rightUnionArray,
108 const TConstantUnion *leftUnionArray)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400109{
110 if (leftNodeType.isArray())
111 {
112 TType typeWithoutArrayness = leftNodeType;
113 typeWithoutArrayness.clearArrayness();
114
115 size_t arraySize = leftNodeType.getArraySize();
116
117 for (size_t i = 0; i < arraySize; ++i)
118 {
119 size_t offset = typeWithoutArrayness.getObjectSize() * i;
120 if (!CompareStruct(typeWithoutArrayness,
121 &rightUnionArray[offset],
122 &leftUnionArray[offset]))
123 {
124 return false;
125 }
126 }
127 }
128 else
129 {
130 return CompareStruct(leftNodeType, rightUnionArray, leftUnionArray);
131 }
132 return true;
133}
134
Arun Patole274f0702015-05-05 13:33:30 +0530135TConstantUnion *Vectorize(const TConstantUnion &constant, size_t size)
136{
137 TConstantUnion *constUnion = new TConstantUnion[size];
138 for (unsigned int i = 0; i < size; ++i)
139 constUnion[i] = constant;
140
141 return constUnion;
142}
143
Jamie Madillb1a85f42014-08-19 15:23:24 -0400144} // namespace anonymous
145
146
147////////////////////////////////////////////////////////////////
148//
149// Member functions of the nodes used for building the tree.
150//
151////////////////////////////////////////////////////////////////
152
Olli Etuahod2a67b92014-10-21 16:42:57 +0300153void TIntermTyped::setTypePreservePrecision(const TType &t)
154{
155 TPrecision precision = getPrecision();
156 mType = t;
157 ASSERT(mType.getBasicType() != EbtBool || precision == EbpUndefined);
158 mType.setPrecision(precision);
159}
160
Jamie Madillb1a85f42014-08-19 15:23:24 -0400161#define REPLACE_IF_IS(node, type, original, replacement) \
162 if (node == original) { \
163 node = static_cast<type *>(replacement); \
164 return true; \
165 }
166
167bool TIntermLoop::replaceChildNode(
168 TIntermNode *original, TIntermNode *replacement)
169{
170 REPLACE_IF_IS(mInit, TIntermNode, original, replacement);
171 REPLACE_IF_IS(mCond, TIntermTyped, original, replacement);
172 REPLACE_IF_IS(mExpr, TIntermTyped, original, replacement);
173 REPLACE_IF_IS(mBody, TIntermNode, original, replacement);
174 return false;
175}
176
Jamie Madillb1a85f42014-08-19 15:23:24 -0400177bool TIntermBranch::replaceChildNode(
178 TIntermNode *original, TIntermNode *replacement)
179{
180 REPLACE_IF_IS(mExpression, TIntermTyped, original, replacement);
181 return false;
182}
183
Jamie Madillb1a85f42014-08-19 15:23:24 -0400184bool TIntermBinary::replaceChildNode(
185 TIntermNode *original, TIntermNode *replacement)
186{
187 REPLACE_IF_IS(mLeft, TIntermTyped, original, replacement);
188 REPLACE_IF_IS(mRight, TIntermTyped, original, replacement);
189 return false;
190}
191
Jamie Madillb1a85f42014-08-19 15:23:24 -0400192bool TIntermUnary::replaceChildNode(
193 TIntermNode *original, TIntermNode *replacement)
194{
195 REPLACE_IF_IS(mOperand, TIntermTyped, original, replacement);
196 return false;
197}
198
Jamie Madillb1a85f42014-08-19 15:23:24 -0400199bool TIntermAggregate::replaceChildNode(
200 TIntermNode *original, TIntermNode *replacement)
201{
202 for (size_t ii = 0; ii < mSequence.size(); ++ii)
203 {
204 REPLACE_IF_IS(mSequence[ii], TIntermNode, original, replacement);
205 }
206 return false;
207}
208
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300209bool TIntermAggregate::replaceChildNodeWithMultiple(TIntermNode *original, TIntermSequence replacements)
210{
211 for (auto it = mSequence.begin(); it < mSequence.end(); ++it)
212 {
213 if (*it == original)
214 {
215 it = mSequence.erase(it);
Olli Etuaho8fee0ab2015-04-23 14:52:46 +0300216 mSequence.insert(it, replacements.begin(), replacements.end());
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300217 return true;
218 }
219 }
220 return false;
221}
222
Olli Etuahoa6f22092015-05-08 18:31:10 +0300223bool TIntermAggregate::insertChildNodes(TIntermSequence::size_type position, TIntermSequence insertions)
224{
225 TIntermSequence::size_type itPosition = 0;
226 for (auto it = mSequence.begin(); it < mSequence.end(); ++it)
227 {
228 if (itPosition == position)
229 {
230 mSequence.insert(it, insertions.begin(), insertions.end());
231 return true;
232 }
233 ++itPosition;
234 }
235 return false;
236}
237
Olli Etuahod2a67b92014-10-21 16:42:57 +0300238void TIntermAggregate::setPrecisionFromChildren()
239{
240 if (getBasicType() == EbtBool)
241 {
242 mType.setPrecision(EbpUndefined);
243 return;
244 }
245
246 TPrecision precision = EbpUndefined;
247 TIntermSequence::iterator childIter = mSequence.begin();
248 while (childIter != mSequence.end())
249 {
250 TIntermTyped *typed = (*childIter)->getAsTyped();
251 if (typed)
252 precision = GetHigherPrecision(typed->getPrecision(), precision);
253 ++childIter;
254 }
255 mType.setPrecision(precision);
256}
257
258void TIntermAggregate::setBuiltInFunctionPrecision()
259{
260 // All built-ins returning bool should be handled as ops, not functions.
261 ASSERT(getBasicType() != EbtBool);
262
263 TPrecision precision = EbpUndefined;
264 TIntermSequence::iterator childIter = mSequence.begin();
265 while (childIter != mSequence.end())
266 {
267 TIntermTyped *typed = (*childIter)->getAsTyped();
268 // ESSL spec section 8: texture functions get their precision from the sampler.
269 if (typed && IsSampler(typed->getBasicType()))
270 {
271 precision = typed->getPrecision();
272 break;
273 }
274 ++childIter;
275 }
276 // ESSL 3.0 spec section 8: textureSize always gets highp precision.
277 // All other functions that take a sampler are assumed to be texture functions.
278 if (mName.find("textureSize") == 0)
279 mType.setPrecision(EbpHigh);
280 else
281 mType.setPrecision(precision);
282}
283
Jamie Madillb1a85f42014-08-19 15:23:24 -0400284bool TIntermSelection::replaceChildNode(
285 TIntermNode *original, TIntermNode *replacement)
286{
287 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
288 REPLACE_IF_IS(mTrueBlock, TIntermNode, original, replacement);
289 REPLACE_IF_IS(mFalseBlock, TIntermNode, original, replacement);
290 return false;
291}
292
Olli Etuahoa3a36662015-02-17 13:46:51 +0200293bool TIntermSwitch::replaceChildNode(
294 TIntermNode *original, TIntermNode *replacement)
295{
296 REPLACE_IF_IS(mInit, TIntermTyped, original, replacement);
297 REPLACE_IF_IS(mStatementList, TIntermAggregate, original, replacement);
298 return false;
299}
300
301bool TIntermCase::replaceChildNode(
302 TIntermNode *original, TIntermNode *replacement)
303{
304 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
305 return false;
306}
307
Jamie Madillb1a85f42014-08-19 15:23:24 -0400308//
309// Say whether or not an operation node changes the value of a variable.
310//
311bool TIntermOperator::isAssignment() const
312{
313 switch (mOp)
314 {
315 case EOpPostIncrement:
316 case EOpPostDecrement:
317 case EOpPreIncrement:
318 case EOpPreDecrement:
319 case EOpAssign:
320 case EOpAddAssign:
321 case EOpSubAssign:
322 case EOpMulAssign:
323 case EOpVectorTimesMatrixAssign:
324 case EOpVectorTimesScalarAssign:
325 case EOpMatrixTimesScalarAssign:
326 case EOpMatrixTimesMatrixAssign:
327 case EOpDivAssign:
Olli Etuahoff805cc2015-02-13 10:59:34 +0200328 case EOpIModAssign:
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200329 case EOpBitShiftLeftAssign:
330 case EOpBitShiftRightAssign:
331 case EOpBitwiseAndAssign:
332 case EOpBitwiseXorAssign:
333 case EOpBitwiseOrAssign:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400334 return true;
335 default:
336 return false;
337 }
338}
339
340//
341// returns true if the operator is for one of the constructors
342//
343bool TIntermOperator::isConstructor() const
344{
345 switch (mOp)
346 {
347 case EOpConstructVec2:
348 case EOpConstructVec3:
349 case EOpConstructVec4:
350 case EOpConstructMat2:
351 case EOpConstructMat3:
352 case EOpConstructMat4:
353 case EOpConstructFloat:
354 case EOpConstructIVec2:
355 case EOpConstructIVec3:
356 case EOpConstructIVec4:
357 case EOpConstructInt:
358 case EOpConstructUVec2:
359 case EOpConstructUVec3:
360 case EOpConstructUVec4:
361 case EOpConstructUInt:
362 case EOpConstructBVec2:
363 case EOpConstructBVec3:
364 case EOpConstructBVec4:
365 case EOpConstructBool:
366 case EOpConstructStruct:
367 return true;
368 default:
369 return false;
370 }
371}
372
373//
374// Make sure the type of a unary operator is appropriate for its
375// combination of operation and operand type.
376//
Olli Etuahof6c694b2015-03-26 14:50:53 +0200377void TIntermUnary::promote(const TType *funcReturnType)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400378{
379 switch (mOp)
380 {
Olli Etuahodca3e792015-03-26 13:24:04 +0200381 case EOpFloatBitsToInt:
382 case EOpFloatBitsToUint:
Olli Etuahoe8d2c072015-01-08 16:33:54 +0200383 case EOpIntBitsToFloat:
384 case EOpUintBitsToFloat:
Olli Etuahodca3e792015-03-26 13:24:04 +0200385 case EOpPackSnorm2x16:
386 case EOpPackUnorm2x16:
387 case EOpPackHalf2x16:
Olli Etuaho7700ff62015-01-15 12:16:29 +0200388 case EOpUnpackSnorm2x16:
389 case EOpUnpackUnorm2x16:
Olli Etuahodca3e792015-03-26 13:24:04 +0200390 mType.setPrecision(EbpHigh);
Arun Patole6b19d762015-02-19 09:40:39 +0530391 break;
Olli Etuahodca3e792015-03-26 13:24:04 +0200392 case EOpUnpackHalf2x16:
393 mType.setPrecision(EbpMedium);
394 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400395 default:
Olli Etuahodca3e792015-03-26 13:24:04 +0200396 setType(mOperand->getType());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400397 }
398
Olli Etuahof6c694b2015-03-26 14:50:53 +0200399 if (funcReturnType != nullptr)
400 {
401 if (funcReturnType->getBasicType() == EbtBool)
402 {
403 // Bool types should not have precision.
404 setType(*funcReturnType);
405 }
406 else
407 {
408 // Precision of the node has been set based on the operand.
409 setTypePreservePrecision(*funcReturnType);
410 }
411 }
412
Jamie Madillb1a85f42014-08-19 15:23:24 -0400413 mType.setQualifier(EvqTemporary);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400414}
415
416//
417// Establishes the type of the resultant operation, as well as
418// makes the operator the correct one for the operands.
419//
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200420// For lots of operations it should already be established that the operand
421// combination is valid, but returns false if operator can't work on operands.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400422//
423bool TIntermBinary::promote(TInfoSink &infoSink)
424{
Olli Etuahoe79904c2015-03-18 16:56:42 +0200425 ASSERT(mLeft->isArray() == mRight->isArray());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400426
Jamie Madillb1a85f42014-08-19 15:23:24 -0400427 //
428 // Base assumption: just make the type the same as the left
429 // operand. Then only deviations from this need be coded.
430 //
431 setType(mLeft->getType());
432
433 // The result gets promoted to the highest precision.
434 TPrecision higherPrecision = GetHigherPrecision(
435 mLeft->getPrecision(), mRight->getPrecision());
436 getTypePointer()->setPrecision(higherPrecision);
437
438 // Binary operations results in temporary variables unless both
439 // operands are const.
440 if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst)
441 {
442 getTypePointer()->setQualifier(EvqTemporary);
443 }
444
445 const int nominalSize =
446 std::max(mLeft->getNominalSize(), mRight->getNominalSize());
447
448 //
449 // All scalars or structs. Code after this test assumes this case is removed!
450 //
451 if (nominalSize == 1)
452 {
453 switch (mOp)
454 {
455 //
456 // Promote to conditional
457 //
458 case EOpEqual:
459 case EOpNotEqual:
460 case EOpLessThan:
461 case EOpGreaterThan:
462 case EOpLessThanEqual:
463 case EOpGreaterThanEqual:
464 setType(TType(EbtBool, EbpUndefined));
465 break;
466
467 //
468 // And and Or operate on conditionals
469 //
470 case EOpLogicalAnd:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200471 case EOpLogicalXor:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400472 case EOpLogicalOr:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200473 ASSERT(mLeft->getBasicType() == EbtBool && mRight->getBasicType() == EbtBool);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400474 setType(TType(EbtBool, EbpUndefined));
475 break;
476
477 default:
478 break;
479 }
480 return true;
481 }
482
483 // If we reach here, at least one of the operands is vector or matrix.
484 // The other operand could be a scalar, vector, or matrix.
485 // Can these two operands be combined?
486 //
487 TBasicType basicType = mLeft->getBasicType();
488 switch (mOp)
489 {
490 case EOpMul:
491 if (!mLeft->isMatrix() && mRight->isMatrix())
492 {
493 if (mLeft->isVector())
494 {
495 mOp = EOpVectorTimesMatrix;
496 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700497 static_cast<unsigned char>(mRight->getCols()), 1));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400498 }
499 else
500 {
501 mOp = EOpMatrixTimesScalar;
502 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700503 static_cast<unsigned char>(mRight->getCols()), static_cast<unsigned char>(mRight->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400504 }
505 }
506 else if (mLeft->isMatrix() && !mRight->isMatrix())
507 {
508 if (mRight->isVector())
509 {
510 mOp = EOpMatrixTimesVector;
511 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700512 static_cast<unsigned char>(mLeft->getRows()), 1));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400513 }
514 else
515 {
516 mOp = EOpMatrixTimesScalar;
517 }
518 }
519 else if (mLeft->isMatrix() && mRight->isMatrix())
520 {
521 mOp = EOpMatrixTimesMatrix;
522 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700523 static_cast<unsigned char>(mRight->getCols()), static_cast<unsigned char>(mLeft->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400524 }
525 else if (!mLeft->isMatrix() && !mRight->isMatrix())
526 {
527 if (mLeft->isVector() && mRight->isVector())
528 {
529 // leave as component product
530 }
531 else if (mLeft->isVector() || mRight->isVector())
532 {
533 mOp = EOpVectorTimesScalar;
534 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700535 static_cast<unsigned char>(nominalSize), 1));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400536 }
537 }
538 else
539 {
540 infoSink.info.message(EPrefixInternalError, getLine(),
541 "Missing elses");
542 return false;
543 }
544
545 if (!ValidateMultiplication(mOp, mLeft->getType(), mRight->getType()))
546 {
547 return false;
548 }
549 break;
550
551 case EOpMulAssign:
552 if (!mLeft->isMatrix() && mRight->isMatrix())
553 {
554 if (mLeft->isVector())
555 {
556 mOp = EOpVectorTimesMatrixAssign;
557 }
558 else
559 {
560 return false;
561 }
562 }
563 else if (mLeft->isMatrix() && !mRight->isMatrix())
564 {
565 if (mRight->isVector())
566 {
567 return false;
568 }
569 else
570 {
571 mOp = EOpMatrixTimesScalarAssign;
572 }
573 }
574 else if (mLeft->isMatrix() && mRight->isMatrix())
575 {
576 mOp = EOpMatrixTimesMatrixAssign;
577 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700578 static_cast<unsigned char>(mRight->getCols()), static_cast<unsigned char>(mLeft->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400579 }
580 else if (!mLeft->isMatrix() && !mRight->isMatrix())
581 {
582 if (mLeft->isVector() && mRight->isVector())
583 {
584 // leave as component product
585 }
586 else if (mLeft->isVector() || mRight->isVector())
587 {
588 if (!mLeft->isVector())
589 return false;
590 mOp = EOpVectorTimesScalarAssign;
591 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700592 static_cast<unsigned char>(mLeft->getNominalSize()), 1));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400593 }
594 }
595 else
596 {
597 infoSink.info.message(EPrefixInternalError, getLine(),
598 "Missing elses");
599 return false;
600 }
601
602 if (!ValidateMultiplication(mOp, mLeft->getType(), mRight->getType()))
603 {
604 return false;
605 }
606 break;
607
608 case EOpAssign:
609 case EOpInitialize:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200610 // No more additional checks are needed.
611 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
612 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
613 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400614 case EOpAdd:
615 case EOpSub:
616 case EOpDiv:
Olli Etuahoff805cc2015-02-13 10:59:34 +0200617 case EOpIMod:
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200618 case EOpBitShiftLeft:
619 case EOpBitShiftRight:
620 case EOpBitwiseAnd:
621 case EOpBitwiseXor:
622 case EOpBitwiseOr:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400623 case EOpAddAssign:
624 case EOpSubAssign:
625 case EOpDivAssign:
Olli Etuahoff805cc2015-02-13 10:59:34 +0200626 case EOpIModAssign:
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200627 case EOpBitShiftLeftAssign:
628 case EOpBitShiftRightAssign:
629 case EOpBitwiseAndAssign:
630 case EOpBitwiseXorAssign:
631 case EOpBitwiseOrAssign:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400632 if ((mLeft->isMatrix() && mRight->isVector()) ||
633 (mLeft->isVector() && mRight->isMatrix()))
634 {
635 return false;
636 }
637
638 // Are the sizes compatible?
639 if (mLeft->getNominalSize() != mRight->getNominalSize() ||
640 mLeft->getSecondarySize() != mRight->getSecondarySize())
641 {
Olli Etuaho6c850472014-12-02 16:23:17 +0200642 // If the nominal sizes of operands do not match:
643 // One of them must be a scalar.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400644 if (!mLeft->isScalar() && !mRight->isScalar())
645 return false;
646
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200647 // In the case of compound assignment other than multiply-assign,
648 // the right side needs to be a scalar. Otherwise a vector/matrix
649 // would be assigned to a scalar. A scalar can't be shifted by a
650 // vector either.
Olli Etuaho6c850472014-12-02 16:23:17 +0200651 if (!mRight->isScalar() &&
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200652 (isAssignment() ||
653 mOp == EOpBitShiftLeft ||
654 mOp == EOpBitShiftRight))
Olli Etuaho6c850472014-12-02 16:23:17 +0200655 return false;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400656 }
657
658 {
659 const int secondarySize = std::max(
660 mLeft->getSecondarySize(), mRight->getSecondarySize());
661 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700662 static_cast<unsigned char>(nominalSize), static_cast<unsigned char>(secondarySize)));
Olli Etuahoe79904c2015-03-18 16:56:42 +0200663 if (mLeft->isArray())
664 {
665 ASSERT(mLeft->getArraySize() == mRight->getArraySize());
666 mType.setArraySize(mLeft->getArraySize());
667 }
Jamie Madillb1a85f42014-08-19 15:23:24 -0400668 }
669 break;
670
671 case EOpEqual:
672 case EOpNotEqual:
673 case EOpLessThan:
674 case EOpGreaterThan:
675 case EOpLessThanEqual:
676 case EOpGreaterThanEqual:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200677 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
678 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400679 setType(TType(EbtBool, EbpUndefined));
680 break;
681
682 default:
683 return false;
684 }
685 return true;
686}
687
688//
689// The fold functions see if an operation on a constant can be done in place,
690// without generating run-time code.
691//
692// Returns the node to keep using, which may or may not be the node passed in.
693//
694TIntermTyped *TIntermConstantUnion::fold(
Olli Etuaho2cb7b832015-04-23 20:27:44 +0300695 TOperator op, TIntermConstantUnion *rightNode, TInfoSink &infoSink)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400696{
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400697 TConstantUnion *unionArray = getUnionArrayPointer();
Jamie Madillb1a85f42014-08-19 15:23:24 -0400698
699 if (!unionArray)
Arun Patolefddc2112015-04-22 13:28:10 +0530700 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400701
702 size_t objectSize = getType().getObjectSize();
703
Olli Etuaho2cb7b832015-04-23 20:27:44 +0300704 if (rightNode)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400705 {
706 // binary operations
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400707 TConstantUnion *rightUnionArray = rightNode->getUnionArrayPointer();
Jamie Madillb1a85f42014-08-19 15:23:24 -0400708 TType returnType = getType();
709
710 if (!rightUnionArray)
Arun Patolefddc2112015-04-22 13:28:10 +0530711 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400712
Olli Etuaho2cb7b832015-04-23 20:27:44 +0300713 // for a case like float f = vec4(2, 3, 4, 5) + 1.2;
714 if (rightNode->getType().getObjectSize() == 1 && objectSize > 1)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400715 {
Arun Patole274f0702015-05-05 13:33:30 +0530716 rightUnionArray = Vectorize(*rightNode->getUnionArrayPointer(), objectSize);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400717 returnType = getType();
718 }
Olli Etuaho2cb7b832015-04-23 20:27:44 +0300719 else if (rightNode->getType().getObjectSize() > 1 && objectSize == 1)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400720 {
Olli Etuaho2cb7b832015-04-23 20:27:44 +0300721 // for a case like float f = 1.2 + vec4(2, 3, 4, 5);
Arun Patole274f0702015-05-05 13:33:30 +0530722 unionArray = Vectorize(*getUnionArrayPointer(), rightNode->getType().getObjectSize());
Olli Etuaho2cb7b832015-04-23 20:27:44 +0300723 returnType = rightNode->getType();
724 objectSize = rightNode->getType().getObjectSize();
Jamie Madillb1a85f42014-08-19 15:23:24 -0400725 }
726
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400727 TConstantUnion *tempConstArray = nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400728 TIntermConstantUnion *tempNode;
729
730 bool boolNodeFlag = false;
731 switch(op)
732 {
733 case EOpAdd:
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400734 tempConstArray = new TConstantUnion[objectSize];
Jamie Madillb1a85f42014-08-19 15:23:24 -0400735 for (size_t i = 0; i < objectSize; i++)
736 tempConstArray[i] = unionArray[i] + rightUnionArray[i];
737 break;
738 case EOpSub:
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400739 tempConstArray = new TConstantUnion[objectSize];
Jamie Madillb1a85f42014-08-19 15:23:24 -0400740 for (size_t i = 0; i < objectSize; i++)
741 tempConstArray[i] = unionArray[i] - rightUnionArray[i];
742 break;
743
744 case EOpMul:
745 case EOpVectorTimesScalar:
746 case EOpMatrixTimesScalar:
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400747 tempConstArray = new TConstantUnion[objectSize];
Jamie Madillb1a85f42014-08-19 15:23:24 -0400748 for (size_t i = 0; i < objectSize; i++)
749 tempConstArray[i] = unionArray[i] * rightUnionArray[i];
750 break;
751
752 case EOpMatrixTimesMatrix:
753 {
754 if (getType().getBasicType() != EbtFloat ||
Olli Etuaho2cb7b832015-04-23 20:27:44 +0300755 rightNode->getBasicType() != EbtFloat)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400756 {
757 infoSink.info.message(
758 EPrefixInternalError, getLine(),
759 "Constant Folding cannot be done for matrix multiply");
Arun Patolefddc2112015-04-22 13:28:10 +0530760 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400761 }
762
763 const int leftCols = getCols();
764 const int leftRows = getRows();
Olli Etuaho2cb7b832015-04-23 20:27:44 +0300765 const int rightCols = rightNode->getType().getCols();
766 const int rightRows = rightNode->getType().getRows();
Jamie Madillb1a85f42014-08-19 15:23:24 -0400767 const int resultCols = rightCols;
768 const int resultRows = leftRows;
769
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400770 tempConstArray = new TConstantUnion[resultCols * resultRows];
Jamie Madillb1a85f42014-08-19 15:23:24 -0400771 for (int row = 0; row < resultRows; row++)
772 {
773 for (int column = 0; column < resultCols; column++)
774 {
775 tempConstArray[resultRows * column + row].setFConst(0.0f);
776 for (int i = 0; i < leftCols; i++)
777 {
778 tempConstArray[resultRows * column + row].setFConst(
779 tempConstArray[resultRows * column + row].getFConst() +
780 unionArray[i * leftRows + row].getFConst() *
781 rightUnionArray[column * rightRows + i].getFConst());
782 }
783 }
784 }
785
786 // update return type for matrix product
Minmin Gong794e0002015-04-07 18:31:54 -0700787 returnType.setPrimarySize(static_cast<unsigned char>(resultCols));
788 returnType.setSecondarySize(static_cast<unsigned char>(resultRows));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400789 }
790 break;
791
792 case EOpDiv:
Olli Etuahoff805cc2015-02-13 10:59:34 +0200793 case EOpIMod:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400794 {
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400795 tempConstArray = new TConstantUnion[objectSize];
Jamie Madillb1a85f42014-08-19 15:23:24 -0400796 for (size_t i = 0; i < objectSize; i++)
797 {
798 switch (getType().getBasicType())
799 {
800 case EbtFloat:
801 if (rightUnionArray[i] == 0.0f)
802 {
803 infoSink.info.message(
804 EPrefixWarning, getLine(),
805 "Divide by zero error during constant folding");
806 tempConstArray[i].setFConst(
807 unionArray[i].getFConst() < 0 ? -FLT_MAX : FLT_MAX);
808 }
809 else
810 {
Olli Etuaho3eab00a2015-02-12 16:02:39 +0200811 ASSERT(op == EOpDiv);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400812 tempConstArray[i].setFConst(
813 unionArray[i].getFConst() /
814 rightUnionArray[i].getFConst());
815 }
816 break;
817
818 case EbtInt:
819 if (rightUnionArray[i] == 0)
820 {
821 infoSink.info.message(
822 EPrefixWarning, getLine(),
823 "Divide by zero error during constant folding");
824 tempConstArray[i].setIConst(INT_MAX);
825 }
826 else
827 {
Olli Etuaho3eab00a2015-02-12 16:02:39 +0200828 if (op == EOpDiv)
829 {
830 tempConstArray[i].setIConst(
831 unionArray[i].getIConst() /
832 rightUnionArray[i].getIConst());
833 }
834 else
835 {
836 ASSERT(op == EOpIMod);
837 tempConstArray[i].setIConst(
838 unionArray[i].getIConst() %
839 rightUnionArray[i].getIConst());
840 }
Jamie Madillb1a85f42014-08-19 15:23:24 -0400841 }
842 break;
843
844 case EbtUInt:
845 if (rightUnionArray[i] == 0)
846 {
847 infoSink.info.message(
848 EPrefixWarning, getLine(),
849 "Divide by zero error during constant folding");
850 tempConstArray[i].setUConst(UINT_MAX);
851 }
852 else
853 {
Olli Etuaho3eab00a2015-02-12 16:02:39 +0200854 if (op == EOpDiv)
855 {
856 tempConstArray[i].setUConst(
857 unionArray[i].getUConst() /
858 rightUnionArray[i].getUConst());
859 }
860 else
861 {
862 ASSERT(op == EOpIMod);
863 tempConstArray[i].setUConst(
864 unionArray[i].getUConst() %
865 rightUnionArray[i].getUConst());
866 }
Jamie Madillb1a85f42014-08-19 15:23:24 -0400867 }
868 break;
869
870 default:
871 infoSink.info.message(
872 EPrefixInternalError, getLine(),
873 "Constant folding cannot be done for \"/\"");
Arun Patolefddc2112015-04-22 13:28:10 +0530874 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400875 }
876 }
877 }
878 break;
879
880 case EOpMatrixTimesVector:
881 {
Olli Etuaho2cb7b832015-04-23 20:27:44 +0300882 if (rightNode->getBasicType() != EbtFloat)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400883 {
884 infoSink.info.message(
885 EPrefixInternalError, getLine(),
886 "Constant Folding cannot be done for matrix times vector");
Arun Patolefddc2112015-04-22 13:28:10 +0530887 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400888 }
889
890 const int matrixCols = getCols();
891 const int matrixRows = getRows();
892
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400893 tempConstArray = new TConstantUnion[matrixRows];
Jamie Madillb1a85f42014-08-19 15:23:24 -0400894
895 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
896 {
897 tempConstArray[matrixRow].setFConst(0.0f);
898 for (int col = 0; col < matrixCols; col++)
899 {
900 tempConstArray[matrixRow].setFConst(
901 tempConstArray[matrixRow].getFConst() +
902 unionArray[col * matrixRows + matrixRow].getFConst() *
903 rightUnionArray[col].getFConst());
904 }
905 }
906
Olli Etuaho2cb7b832015-04-23 20:27:44 +0300907 returnType = rightNode->getType();
Minmin Gong794e0002015-04-07 18:31:54 -0700908 returnType.setPrimarySize(static_cast<unsigned char>(matrixRows));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400909
910 tempNode = new TIntermConstantUnion(tempConstArray, returnType);
911 tempNode->setLine(getLine());
912
913 return tempNode;
914 }
915
916 case EOpVectorTimesMatrix:
917 {
918 if (getType().getBasicType() != EbtFloat)
919 {
920 infoSink.info.message(
921 EPrefixInternalError, getLine(),
922 "Constant Folding cannot be done for vector times matrix");
Arun Patolefddc2112015-04-22 13:28:10 +0530923 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400924 }
925
Olli Etuaho2cb7b832015-04-23 20:27:44 +0300926 const int matrixCols = rightNode->getType().getCols();
927 const int matrixRows = rightNode->getType().getRows();
Jamie Madillb1a85f42014-08-19 15:23:24 -0400928
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400929 tempConstArray = new TConstantUnion[matrixCols];
Jamie Madillb1a85f42014-08-19 15:23:24 -0400930
931 for (int matrixCol = 0; matrixCol < matrixCols; matrixCol++)
932 {
933 tempConstArray[matrixCol].setFConst(0.0f);
934 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
935 {
936 tempConstArray[matrixCol].setFConst(
937 tempConstArray[matrixCol].getFConst() +
938 unionArray[matrixRow].getFConst() *
939 rightUnionArray[matrixCol * matrixRows + matrixRow].getFConst());
940 }
941 }
942
Minmin Gong794e0002015-04-07 18:31:54 -0700943 returnType.setPrimarySize(static_cast<unsigned char>(matrixCols));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400944 }
945 break;
946
947 case EOpLogicalAnd:
948 // this code is written for possible future use,
949 // will not get executed currently
950 {
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400951 tempConstArray = new TConstantUnion[objectSize];
Jamie Madillb1a85f42014-08-19 15:23:24 -0400952 for (size_t i = 0; i < objectSize; i++)
953 {
954 tempConstArray[i] = unionArray[i] && rightUnionArray[i];
955 }
956 }
957 break;
958
959 case EOpLogicalOr:
960 // this code is written for possible future use,
961 // will not get executed currently
962 {
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400963 tempConstArray = new TConstantUnion[objectSize];
Jamie Madillb1a85f42014-08-19 15:23:24 -0400964 for (size_t i = 0; i < objectSize; i++)
965 {
966 tempConstArray[i] = unionArray[i] || rightUnionArray[i];
967 }
968 }
969 break;
970
971 case EOpLogicalXor:
972 {
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400973 tempConstArray = new TConstantUnion[objectSize];
Jamie Madillb1a85f42014-08-19 15:23:24 -0400974 for (size_t i = 0; i < objectSize; i++)
975 {
976 switch (getType().getBasicType())
977 {
978 case EbtBool:
979 tempConstArray[i].setBConst(
980 unionArray[i] == rightUnionArray[i] ? false : true);
981 break;
982 default:
983 UNREACHABLE();
984 break;
985 }
986 }
987 }
988 break;
989
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200990 case EOpBitwiseAnd:
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400991 tempConstArray = new TConstantUnion[objectSize];
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200992 for (size_t i = 0; i < objectSize; i++)
993 tempConstArray[i] = unionArray[i] & rightUnionArray[i];
994 break;
995 case EOpBitwiseXor:
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400996 tempConstArray = new TConstantUnion[objectSize];
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200997 for (size_t i = 0; i < objectSize; i++)
998 tempConstArray[i] = unionArray[i] ^ rightUnionArray[i];
999 break;
1000 case EOpBitwiseOr:
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001001 tempConstArray = new TConstantUnion[objectSize];
Olli Etuaho31b5fc62015-01-16 12:13:36 +02001002 for (size_t i = 0; i < objectSize; i++)
1003 tempConstArray[i] = unionArray[i] | rightUnionArray[i];
1004 break;
1005 case EOpBitShiftLeft:
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001006 tempConstArray = new TConstantUnion[objectSize];
Olli Etuaho31b5fc62015-01-16 12:13:36 +02001007 for (size_t i = 0; i < objectSize; i++)
1008 tempConstArray[i] = unionArray[i] << rightUnionArray[i];
1009 break;
1010 case EOpBitShiftRight:
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001011 tempConstArray = new TConstantUnion[objectSize];
Olli Etuaho31b5fc62015-01-16 12:13:36 +02001012 for (size_t i = 0; i < objectSize; i++)
1013 tempConstArray[i] = unionArray[i] >> rightUnionArray[i];
1014 break;
1015
Jamie Madillb1a85f42014-08-19 15:23:24 -04001016 case EOpLessThan:
1017 ASSERT(objectSize == 1);
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001018 tempConstArray = new TConstantUnion[1];
Jamie Madillb1a85f42014-08-19 15:23:24 -04001019 tempConstArray->setBConst(*unionArray < *rightUnionArray);
1020 returnType = TType(EbtBool, EbpUndefined, EvqConst);
1021 break;
1022
1023 case EOpGreaterThan:
1024 ASSERT(objectSize == 1);
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001025 tempConstArray = new TConstantUnion[1];
Jamie Madillb1a85f42014-08-19 15:23:24 -04001026 tempConstArray->setBConst(*unionArray > *rightUnionArray);
1027 returnType = TType(EbtBool, EbpUndefined, EvqConst);
1028 break;
1029
1030 case EOpLessThanEqual:
1031 {
1032 ASSERT(objectSize == 1);
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001033 TConstantUnion constant;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001034 constant.setBConst(*unionArray > *rightUnionArray);
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001035 tempConstArray = new TConstantUnion[1];
Jamie Madillb1a85f42014-08-19 15:23:24 -04001036 tempConstArray->setBConst(!constant.getBConst());
1037 returnType = TType(EbtBool, EbpUndefined, EvqConst);
1038 break;
1039 }
1040
1041 case EOpGreaterThanEqual:
1042 {
1043 ASSERT(objectSize == 1);
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001044 TConstantUnion constant;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001045 constant.setBConst(*unionArray < *rightUnionArray);
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001046 tempConstArray = new TConstantUnion[1];
Jamie Madillb1a85f42014-08-19 15:23:24 -04001047 tempConstArray->setBConst(!constant.getBConst());
1048 returnType = TType(EbtBool, EbpUndefined, EvqConst);
1049 break;
1050 }
1051
1052 case EOpEqual:
1053 if (getType().getBasicType() == EbtStruct)
1054 {
Olli Etuaho2cb7b832015-04-23 20:27:44 +03001055 if (!CompareStructure(rightNode->getType(),
1056 rightNode->getUnionArrayPointer(),
Jamie Madillb1a85f42014-08-19 15:23:24 -04001057 unionArray))
1058 {
1059 boolNodeFlag = true;
1060 }
1061 }
1062 else
1063 {
1064 for (size_t i = 0; i < objectSize; i++)
1065 {
1066 if (unionArray[i] != rightUnionArray[i])
1067 {
1068 boolNodeFlag = true;
1069 break; // break out of for loop
1070 }
1071 }
1072 }
1073
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001074 tempConstArray = new TConstantUnion[1];
Jamie Madillb1a85f42014-08-19 15:23:24 -04001075 if (!boolNodeFlag)
1076 {
1077 tempConstArray->setBConst(true);
1078 }
1079 else
1080 {
1081 tempConstArray->setBConst(false);
1082 }
1083
1084 tempNode = new TIntermConstantUnion(
1085 tempConstArray, TType(EbtBool, EbpUndefined, EvqConst));
1086 tempNode->setLine(getLine());
1087
1088 return tempNode;
1089
1090 case EOpNotEqual:
1091 if (getType().getBasicType() == EbtStruct)
1092 {
Olli Etuaho2cb7b832015-04-23 20:27:44 +03001093 if (CompareStructure(rightNode->getType(),
1094 rightNode->getUnionArrayPointer(),
Jamie Madillb1a85f42014-08-19 15:23:24 -04001095 unionArray))
1096 {
1097 boolNodeFlag = true;
1098 }
1099 }
1100 else
1101 {
1102 for (size_t i = 0; i < objectSize; i++)
1103 {
1104 if (unionArray[i] == rightUnionArray[i])
1105 {
1106 boolNodeFlag = true;
1107 break; // break out of for loop
1108 }
1109 }
1110 }
1111
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001112 tempConstArray = new TConstantUnion[1];
Jamie Madillb1a85f42014-08-19 15:23:24 -04001113 if (!boolNodeFlag)
1114 {
1115 tempConstArray->setBConst(true);
1116 }
1117 else
1118 {
1119 tempConstArray->setBConst(false);
1120 }
1121
1122 tempNode = new TIntermConstantUnion(
1123 tempConstArray, TType(EbtBool, EbpUndefined, EvqConst));
1124 tempNode->setLine(getLine());
1125
1126 return tempNode;
1127
1128 default:
1129 infoSink.info.message(
1130 EPrefixInternalError, getLine(),
1131 "Invalid operator for constant folding");
Arun Patolefddc2112015-04-22 13:28:10 +05301132 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001133 }
1134 tempNode = new TIntermConstantUnion(tempConstArray, returnType);
1135 tempNode->setLine(getLine());
1136
1137 return tempNode;
1138 }
1139 else
1140 {
1141 //
1142 // Do unary operations
1143 //
1144 TIntermConstantUnion *newNode = 0;
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001145 TConstantUnion* tempConstArray = new TConstantUnion[objectSize];
Jamie Madillb1a85f42014-08-19 15:23:24 -04001146 for (size_t i = 0; i < objectSize; i++)
1147 {
1148 switch(op)
1149 {
1150 case EOpNegative:
1151 switch (getType().getBasicType())
1152 {
1153 case EbtFloat:
1154 tempConstArray[i].setFConst(-unionArray[i].getFConst());
1155 break;
1156 case EbtInt:
1157 tempConstArray[i].setIConst(-unionArray[i].getIConst());
1158 break;
1159 case EbtUInt:
1160 tempConstArray[i].setUConst(static_cast<unsigned int>(
1161 -static_cast<int>(unionArray[i].getUConst())));
1162 break;
1163 default:
1164 infoSink.info.message(
1165 EPrefixInternalError, getLine(),
1166 "Unary operation not folded into constant");
Arun Patolefddc2112015-04-22 13:28:10 +05301167 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001168 }
1169 break;
1170
Zhenyao Mode1e00e2014-10-09 16:55:32 -07001171 case EOpPositive:
1172 switch (getType().getBasicType())
1173 {
1174 case EbtFloat:
1175 tempConstArray[i].setFConst(unionArray[i].getFConst());
1176 break;
1177 case EbtInt:
1178 tempConstArray[i].setIConst(unionArray[i].getIConst());
1179 break;
1180 case EbtUInt:
1181 tempConstArray[i].setUConst(static_cast<unsigned int>(
1182 static_cast<int>(unionArray[i].getUConst())));
1183 break;
1184 default:
1185 infoSink.info.message(
1186 EPrefixInternalError, getLine(),
1187 "Unary operation not folded into constant");
Arun Patolefddc2112015-04-22 13:28:10 +05301188 return nullptr;
Zhenyao Mode1e00e2014-10-09 16:55:32 -07001189 }
1190 break;
1191
Jamie Madillb1a85f42014-08-19 15:23:24 -04001192 case EOpLogicalNot:
1193 // this code is written for possible future use,
1194 // will not get executed currently
1195 switch (getType().getBasicType())
1196 {
1197 case EbtBool:
1198 tempConstArray[i].setBConst(!unionArray[i].getBConst());
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;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001205 }
1206 break;
1207
Olli Etuaho31b5fc62015-01-16 12:13:36 +02001208 case EOpBitwiseNot:
1209 switch (getType().getBasicType())
1210 {
1211 case EbtInt:
1212 tempConstArray[i].setIConst(~unionArray[i].getIConst());
1213 break;
1214 case EbtUInt:
1215 tempConstArray[i].setUConst(~unionArray[i].getUConst());
1216 break;
1217 default:
1218 infoSink.info.message(
1219 EPrefixInternalError, getLine(),
1220 "Unary operation not folded into constant");
Arun Patolefddc2112015-04-22 13:28:10 +05301221 return nullptr;
Olli Etuaho31b5fc62015-01-16 12:13:36 +02001222 }
1223 break;
1224
Arun Patole9dea48f2015-04-02 11:45:09 +05301225 case EOpRadians:
1226 if (getType().getBasicType() == EbtFloat)
1227 {
1228 tempConstArray[i].setFConst(kDegreesToRadiansMultiplier * unionArray[i].getFConst());
1229 break;
1230 }
1231 infoSink.info.message(
1232 EPrefixInternalError, getLine(),
1233 "Unary operation not folded into constant");
1234 return nullptr;
1235
1236 case EOpDegrees:
1237 if (getType().getBasicType() == EbtFloat)
1238 {
1239 tempConstArray[i].setFConst(kRadiansToDegreesMultiplier * unionArray[i].getFConst());
1240 break;
1241 }
1242 infoSink.info.message(
1243 EPrefixInternalError, getLine(),
1244 "Unary operation not folded into constant");
1245 return nullptr;
1246
1247 case EOpSin:
1248 if (!foldFloatTypeUnary(unionArray[i], &sinf, infoSink, &tempConstArray[i]))
1249 return nullptr;
1250 break;
1251
1252 case EOpCos:
1253 if (!foldFloatTypeUnary(unionArray[i], &cosf, infoSink, &tempConstArray[i]))
1254 return nullptr;
1255 break;
1256
1257 case EOpTan:
1258 if (!foldFloatTypeUnary(unionArray[i], &tanf, infoSink, &tempConstArray[i]))
1259 return nullptr;
1260 break;
1261
1262 case EOpAsin:
1263 // For asin(x), results are undefined if |x| > 1, we are choosing to set result to 0.
1264 if (getType().getBasicType() == EbtFloat && fabsf(unionArray[i].getFConst()) > 1.0f)
1265 tempConstArray[i].setFConst(0.0f);
1266 else if (!foldFloatTypeUnary(unionArray[i], &asinf, infoSink, &tempConstArray[i]))
1267 return nullptr;
1268 break;
1269
1270 case EOpAcos:
1271 // For acos(x), results are undefined if |x| > 1, we are choosing to set result to 0.
1272 if (getType().getBasicType() == EbtFloat && fabsf(unionArray[i].getFConst()) > 1.0f)
1273 tempConstArray[i].setFConst(0.0f);
1274 else if (!foldFloatTypeUnary(unionArray[i], &acosf, infoSink, &tempConstArray[i]))
1275 return nullptr;
1276 break;
1277
1278 case EOpAtan:
1279 if (!foldFloatTypeUnary(unionArray[i], &atanf, infoSink, &tempConstArray[i]))
1280 return nullptr;
1281 break;
1282
1283 case EOpSinh:
1284 if (!foldFloatTypeUnary(unionArray[i], &sinhf, infoSink, &tempConstArray[i]))
1285 return nullptr;
1286 break;
1287
1288 case EOpCosh:
1289 if (!foldFloatTypeUnary(unionArray[i], &coshf, infoSink, &tempConstArray[i]))
1290 return nullptr;
1291 break;
1292
1293 case EOpTanh:
1294 if (!foldFloatTypeUnary(unionArray[i], &tanhf, infoSink, &tempConstArray[i]))
1295 return nullptr;
1296 break;
1297
1298 case EOpAsinh:
1299 if (!foldFloatTypeUnary(unionArray[i], &asinhf, infoSink, &tempConstArray[i]))
1300 return nullptr;
1301 break;
1302
1303 case EOpAcosh:
1304 // For acosh(x), results are undefined if x < 1, we are choosing to set result to 0.
1305 if (getType().getBasicType() == EbtFloat && unionArray[i].getFConst() < 1.0f)
1306 tempConstArray[i].setFConst(0.0f);
1307 else if (!foldFloatTypeUnary(unionArray[i], &acoshf, infoSink, &tempConstArray[i]))
1308 return nullptr;
1309 break;
1310
1311 case EOpAtanh:
1312 // For atanh(x), results are undefined if |x| >= 1, we are choosing to set result to 0.
1313 if (getType().getBasicType() == EbtFloat && fabsf(unionArray[i].getFConst()) >= 1.0f)
1314 tempConstArray[i].setFConst(0.0f);
1315 else if (!foldFloatTypeUnary(unionArray[i], &atanhf, infoSink, &tempConstArray[i]))
1316 return nullptr;
1317 break;
1318
Arun Patole97dc22e2015-04-06 17:35:38 +05301319 case EOpAbs:
1320 switch (getType().getBasicType())
1321 {
1322 case EbtFloat:
1323 tempConstArray[i].setFConst(fabsf(unionArray[i].getFConst()));
1324 break;
1325 case EbtInt:
1326 tempConstArray[i].setIConst(abs(unionArray[i].getIConst()));
1327 break;
1328 default:
1329 infoSink.info.message(
1330 EPrefixInternalError, getLine(),
1331 "Unary operation not folded into constant");
1332 return nullptr;
1333 }
1334 break;
1335
1336 case EOpSign:
1337 switch (getType().getBasicType())
1338 {
1339 case EbtFloat:
1340 {
1341 float fConst = unionArray[i].getFConst();
1342 float fResult = 0.0f;
1343 if (fConst > 0.0f)
1344 fResult = 1.0f;
1345 else if (fConst < 0.0f)
1346 fResult = -1.0f;
1347 tempConstArray[i].setFConst(fResult);
1348 }
1349 break;
1350 case EbtInt:
1351 {
1352 int iConst = unionArray[i].getIConst();
1353 int iResult = 0;
1354 if (iConst > 0)
1355 iResult = 1;
1356 else if (iConst < 0)
1357 iResult = -1;
1358 tempConstArray[i].setIConst(iResult);
1359 }
1360 break;
1361 default:
1362 infoSink.info.message(
1363 EPrefixInternalError, getLine(),
1364 "Unary operation not folded into constant");
1365 return nullptr;
1366 }
1367 break;
1368
1369 case EOpFloor:
1370 if (!foldFloatTypeUnary(unionArray[i], &floorf, infoSink, &tempConstArray[i]))
1371 return nullptr;
1372 break;
1373
1374 case EOpTrunc:
1375 if (!foldFloatTypeUnary(unionArray[i], &truncf, infoSink, &tempConstArray[i]))
1376 return nullptr;
1377 break;
1378
1379 case EOpRound:
1380 if (!foldFloatTypeUnary(unionArray[i], &roundf, infoSink, &tempConstArray[i]))
1381 return nullptr;
1382 break;
1383
1384 case EOpRoundEven:
1385 if (getType().getBasicType() == EbtFloat)
1386 {
1387 float x = unionArray[i].getFConst();
1388 float result;
1389 float fractPart = modff(x, &result);
1390 if (fabsf(fractPart) == 0.5f)
1391 result = 2.0f * roundf(x / 2.0f);
1392 else
1393 result = roundf(x);
1394 tempConstArray[i].setFConst(result);
1395 break;
1396 }
1397 infoSink.info.message(
1398 EPrefixInternalError, getLine(),
1399 "Unary operation not folded into constant");
1400 return nullptr;
1401
1402 case EOpCeil:
1403 if (!foldFloatTypeUnary(unionArray[i], &ceilf, infoSink, &tempConstArray[i]))
1404 return nullptr;
1405 break;
1406
1407 case EOpFract:
1408 if (getType().getBasicType() == EbtFloat)
1409 {
1410 float x = unionArray[i].getFConst();
1411 tempConstArray[i].setFConst(x - floorf(x));
1412 break;
1413 }
1414 infoSink.info.message(
1415 EPrefixInternalError, getLine(),
1416 "Unary operation not folded into constant");
1417 return nullptr;
1418
Arun Patole28eb65e2015-04-06 17:29:48 +05301419 case EOpExp:
1420 if (!foldFloatTypeUnary(unionArray[i], &expf, infoSink, &tempConstArray[i]))
1421 return nullptr;
1422 break;
1423
1424 case EOpLog:
1425 // For log(x), results are undefined if x <= 0, we are choosing to set result to 0.
1426 if (getType().getBasicType() == EbtFloat && unionArray[i].getFConst() <= 0.0f)
1427 tempConstArray[i].setFConst(0.0f);
1428 else if (!foldFloatTypeUnary(unionArray[i], &logf, infoSink, &tempConstArray[i]))
1429 return nullptr;
1430 break;
1431
1432 case EOpExp2:
1433 if (!foldFloatTypeUnary(unionArray[i], &exp2f, infoSink, &tempConstArray[i]))
1434 return nullptr;
1435 break;
1436
1437 case EOpLog2:
1438 // For log2(x), results are undefined if x <= 0, we are choosing to set result to 0.
1439 // And log2f is not available on some plarforms like old android, so just using log(x)/log(2) here.
1440 if (getType().getBasicType() == EbtFloat && unionArray[i].getFConst() <= 0.0f)
1441 tempConstArray[i].setFConst(0.0f);
1442 else if (!foldFloatTypeUnary(unionArray[i], &logf, infoSink, &tempConstArray[i]))
1443 return nullptr;
1444 else
1445 tempConstArray[i].setFConst(tempConstArray[i].getFConst() / logf(2.0f));
1446 break;
1447
1448 case EOpSqrt:
1449 // For sqrt(x), results are undefined if x < 0, we are choosing to set result to 0.
1450 if (getType().getBasicType() == EbtFloat && unionArray[i].getFConst() < 0.0f)
1451 tempConstArray[i].setFConst(0.0f);
1452 else if (!foldFloatTypeUnary(unionArray[i], &sqrtf, infoSink, &tempConstArray[i]))
1453 return nullptr;
1454 break;
1455
1456 case EOpInverseSqrt:
1457 // There is no stdlib built-in function equavalent for GLES built-in inversesqrt(),
1458 // so getting the square root first using builtin function sqrt() and then taking its inverse.
1459 // Also, for inversesqrt(x), results are undefined if x <= 0, we are choosing to set result to 0.
1460 if (getType().getBasicType() == EbtFloat && unionArray[i].getFConst() <= 0.0f)
1461 tempConstArray[i].setFConst(0.0f);
1462 else if (!foldFloatTypeUnary(unionArray[i], &sqrtf, infoSink, &tempConstArray[i]))
1463 return nullptr;
1464 else
1465 tempConstArray[i].setFConst(1.0f / tempConstArray[i].getFConst());
1466 break;
1467
Jamie Madillb1a85f42014-08-19 15:23:24 -04001468 default:
Arun Patolefddc2112015-04-22 13:28:10 +05301469 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001470 }
1471 }
1472 newNode = new TIntermConstantUnion(tempConstArray, getType());
1473 newNode->setLine(getLine());
1474 return newNode;
1475 }
1476}
1477
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001478bool TIntermConstantUnion::foldFloatTypeUnary(const TConstantUnion &parameter, FloatTypeUnaryFunc builtinFunc,
1479 TInfoSink &infoSink, TConstantUnion *result) const
Arun Patole9dea48f2015-04-02 11:45:09 +05301480{
1481 ASSERT(builtinFunc);
1482
1483 if (getType().getBasicType() == EbtFloat)
1484 {
1485 result->setFConst(builtinFunc(parameter.getFConst()));
1486 return true;
1487 }
1488
1489 infoSink.info.message(
1490 EPrefixInternalError, getLine(),
1491 "Unary operation not folded into constant");
1492 return false;
1493}
1494
Jamie Madillb1a85f42014-08-19 15:23:24 -04001495// static
Arun Patole274f0702015-05-05 13:33:30 +05301496TIntermTyped *TIntermConstantUnion::FoldAggregateBuiltIn(TOperator op, TIntermAggregate *aggregate)
1497{
1498 TIntermSequence *sequence = aggregate->getSequence();
1499 unsigned int paramsCount = sequence->size();
1500 std::vector<TConstantUnion *> unionArrays(paramsCount);
1501 std::vector<size_t> objectSizes(paramsCount);
1502 TType *maxSizeType = nullptr;
1503 TBasicType basicType = EbtVoid;
1504 TSourceLoc loc;
1505 for (unsigned int i = 0; i < paramsCount; i++)
1506 {
1507 TIntermConstantUnion *paramConstant = (*sequence)[i]->getAsConstantUnion();
1508 // Make sure that all params are constant before actual constant folding.
1509 if (!paramConstant)
1510 return nullptr;
1511
1512 if (i == 0)
1513 {
1514 basicType = paramConstant->getType().getBasicType();
1515 loc = paramConstant->getLine();
1516 }
1517 unionArrays[i] = paramConstant->getUnionArrayPointer();
1518 objectSizes[i] = paramConstant->getType().getObjectSize();
1519 if (maxSizeType == nullptr || (objectSizes[i] >= maxSizeType->getObjectSize()))
1520 maxSizeType = paramConstant->getTypePointer();
1521 }
1522
1523 size_t maxObjectSize = maxSizeType->getObjectSize();
1524 for (unsigned int i = 0; i < paramsCount; i++)
1525 if (objectSizes[i] != maxObjectSize)
1526 unionArrays[i] = Vectorize(*unionArrays[i], maxObjectSize);
1527
1528 TConstantUnion *tempConstArray = nullptr;
1529 TIntermConstantUnion *tempNode = nullptr;
1530 TType returnType = *maxSizeType;
1531 if (paramsCount == 2)
1532 {
1533 //
1534 // Binary built-in
1535 //
1536 switch (op)
1537 {
1538 case EOpMin:
1539 {
1540 tempConstArray = new TConstantUnion[maxObjectSize];
1541 for (size_t i = 0; i < maxObjectSize; i++)
1542 {
1543 switch (basicType)
1544 {
1545 case EbtFloat:
1546 tempConstArray[i].setFConst(std::min(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
1547 break;
1548 case EbtInt:
1549 tempConstArray[i].setIConst(std::min(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
1550 break;
1551 case EbtUInt:
1552 tempConstArray[i].setUConst(std::min(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
1553 break;
1554 default:
1555 UNREACHABLE();
1556 break;
1557 }
1558 }
1559 }
1560 break;
1561
1562 case EOpMax:
1563 {
1564 tempConstArray = new TConstantUnion[maxObjectSize];
1565 for (size_t i = 0; i < maxObjectSize; i++)
1566 {
1567 switch (basicType)
1568 {
1569 case EbtFloat:
1570 tempConstArray[i].setFConst(std::max(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
1571 break;
1572 case EbtInt:
1573 tempConstArray[i].setIConst(std::max(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
1574 break;
1575 case EbtUInt:
1576 tempConstArray[i].setUConst(std::max(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
1577 break;
1578 default:
1579 UNREACHABLE();
1580 break;
1581 }
1582 }
1583 }
1584 break;
1585
1586 default:
1587 UNREACHABLE();
1588 // TODO: Add constant folding support for other built-in operations that take 2 parameters and not handled above.
1589 return nullptr;
1590 }
1591 }
1592 else if (paramsCount == 3)
1593 {
1594 //
1595 // Ternary built-in
1596 //
1597 switch (op)
1598 {
1599 case EOpClamp:
1600 {
1601 tempConstArray = new TConstantUnion[maxObjectSize];
1602 for (size_t i = 0; i < maxObjectSize; i++)
1603 {
1604 switch (basicType)
1605 {
1606 case EbtFloat:
1607 {
1608 float x = unionArrays[0][i].getFConst();
1609 float min = unionArrays[1][i].getFConst();
1610 float max = unionArrays[2][i].getFConst();
1611 // Results are undefined if min > max.
1612 if (min > max)
1613 tempConstArray[i].setFConst(0.0f);
1614 else
1615 tempConstArray[i].setFConst(gl::clamp(x, min, max));
1616 }
1617 break;
1618 case EbtInt:
1619 {
1620 int x = unionArrays[0][i].getIConst();
1621 int min = unionArrays[1][i].getIConst();
1622 int max = unionArrays[2][i].getIConst();
1623 // Results are undefined if min > max.
1624 if (min > max)
1625 tempConstArray[i].setIConst(0);
1626 else
1627 tempConstArray[i].setIConst(gl::clamp(x, min, max));
1628 }
1629 break;
1630 case EbtUInt:
1631 {
1632 unsigned int x = unionArrays[0][i].getUConst();
1633 unsigned int min = unionArrays[1][i].getUConst();
1634 unsigned int max = unionArrays[2][i].getUConst();
1635 // Results are undefined if min > max.
1636 if (min > max)
1637 tempConstArray[i].setUConst(0u);
1638 else
1639 tempConstArray[i].setUConst(gl::clamp(x, min, max));
1640 }
1641 break;
1642 default:
1643 UNREACHABLE();
1644 break;
1645 }
1646 }
1647 }
1648 break;
1649
1650 default:
1651 UNREACHABLE();
1652 // TODO: Add constant folding support for other built-in operations that take 3 parameters and not handled above.
1653 return nullptr;
1654 }
1655 }
1656
1657 if (tempConstArray)
1658 {
1659 tempNode = new TIntermConstantUnion(tempConstArray, returnType);
1660 tempNode->setLine(loc);
1661 }
1662 return tempNode;
1663}
1664
1665// static
Jamie Madillb1a85f42014-08-19 15:23:24 -04001666TString TIntermTraverser::hash(const TString &name, ShHashFunction64 hashFunction)
1667{
1668 if (hashFunction == NULL || name.empty())
1669 return name;
1670 khronos_uint64_t number = (*hashFunction)(name.c_str(), name.length());
1671 TStringStream stream;
1672 stream << HASHED_NAME_PREFIX << std::hex << number;
1673 TString hashedName = stream.str();
1674 return hashedName;
1675}
Olli Etuaho853dc1a2014-11-06 17:25:48 +02001676
1677void TIntermTraverser::updateTree()
1678{
Olli Etuahoa6f22092015-05-08 18:31:10 +03001679 for (size_t ii = 0; ii < mInsertions.size(); ++ii)
1680 {
1681 const NodeInsertMultipleEntry &insertion = mInsertions[ii];
1682 ASSERT(insertion.parent);
1683 bool inserted = insertion.parent->insertChildNodes(insertion.position, insertion.insertions);
1684 ASSERT(inserted);
1685 UNUSED_ASSERTION_VARIABLE(inserted);
1686 }
Olli Etuaho853dc1a2014-11-06 17:25:48 +02001687 for (size_t ii = 0; ii < mReplacements.size(); ++ii)
1688 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03001689 const NodeUpdateEntry &replacement = mReplacements[ii];
1690 ASSERT(replacement.parent);
1691 bool replaced = replacement.parent->replaceChildNode(
1692 replacement.original, replacement.replacement);
Olli Etuaho853dc1a2014-11-06 17:25:48 +02001693 ASSERT(replaced);
Olli Etuahod57e0db2015-04-24 15:05:08 +03001694 UNUSED_ASSERTION_VARIABLE(replaced);
Olli Etuaho853dc1a2014-11-06 17:25:48 +02001695
Olli Etuahocd94ef92015-04-16 19:18:10 +03001696 if (!replacement.originalBecomesChildOfReplacement)
Olli Etuaho853dc1a2014-11-06 17:25:48 +02001697 {
1698 // In AST traversing, a parent is visited before its children.
Olli Etuahocd94ef92015-04-16 19:18:10 +03001699 // After we replace a node, if its immediate child is to
Olli Etuaho853dc1a2014-11-06 17:25:48 +02001700 // be replaced, we need to make sure we don't update the replaced
1701 // node; instead, we update the replacement node.
1702 for (size_t jj = ii + 1; jj < mReplacements.size(); ++jj)
1703 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03001704 NodeUpdateEntry &replacement2 = mReplacements[jj];
1705 if (replacement2.parent == replacement.original)
1706 replacement2.parent = replacement.replacement;
Olli Etuaho853dc1a2014-11-06 17:25:48 +02001707 }
1708 }
1709 }
Olli Etuahofc0e2bc2015-04-16 13:39:56 +03001710 for (size_t ii = 0; ii < mMultiReplacements.size(); ++ii)
1711 {
1712 const NodeReplaceWithMultipleEntry &replacement = mMultiReplacements[ii];
1713 ASSERT(replacement.parent);
1714 bool replaced = replacement.parent->replaceChildNodeWithMultiple(
1715 replacement.original, replacement.replacements);
1716 ASSERT(replaced);
Olli Etuahod57e0db2015-04-24 15:05:08 +03001717 UNUSED_ASSERTION_VARIABLE(replaced);
Olli Etuahofc0e2bc2015-04-16 13:39:56 +03001718 }
Olli Etuaho853dc1a2014-11-06 17:25:48 +02001719}