blob: aa0f31d1708bfe7516e3d2eb7601b325abad74da [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>
13#include <algorithm>
14
15#include "compiler/translator/HashNames.h"
16#include "compiler/translator/IntermNode.h"
17#include "compiler/translator/SymbolTable.h"
18
19namespace
20{
21
22TPrecision GetHigherPrecision(TPrecision left, TPrecision right)
23{
24 return left > right ? left : right;
25}
26
27bool ValidateMultiplication(TOperator op, const TType &left, const TType &right)
28{
29 switch (op)
30 {
31 case EOpMul:
32 case EOpMulAssign:
33 return left.getNominalSize() == right.getNominalSize() &&
34 left.getSecondarySize() == right.getSecondarySize();
35 case EOpVectorTimesScalar:
36 case EOpVectorTimesScalarAssign:
37 return true;
38 case EOpVectorTimesMatrix:
39 return left.getNominalSize() == right.getRows();
40 case EOpVectorTimesMatrixAssign:
41 return left.getNominalSize() == right.getRows() &&
42 left.getNominalSize() == right.getCols();
43 case EOpMatrixTimesVector:
44 return left.getCols() == right.getNominalSize();
45 case EOpMatrixTimesScalar:
46 case EOpMatrixTimesScalarAssign:
47 return true;
48 case EOpMatrixTimesMatrix:
49 return left.getCols() == right.getRows();
50 case EOpMatrixTimesMatrixAssign:
51 return left.getCols() == right.getCols() &&
52 left.getRows() == right.getRows();
53
54 default:
55 UNREACHABLE();
56 return false;
57 }
58}
59
60bool CompareStructure(const TType& leftNodeType,
61 ConstantUnion *rightUnionArray,
62 ConstantUnion *leftUnionArray);
63
64bool CompareStruct(const TType &leftNodeType,
65 ConstantUnion *rightUnionArray,
66 ConstantUnion *leftUnionArray)
67{
68 const TFieldList &fields = leftNodeType.getStruct()->fields();
69
70 size_t structSize = fields.size();
71 size_t index = 0;
72
73 for (size_t j = 0; j < structSize; j++)
74 {
75 size_t size = fields[j]->type()->getObjectSize();
76 for (size_t i = 0; i < size; i++)
77 {
78 if (fields[j]->type()->getBasicType() == EbtStruct)
79 {
80 if (!CompareStructure(*fields[j]->type(),
81 &rightUnionArray[index],
82 &leftUnionArray[index]))
83 {
84 return false;
85 }
86 }
87 else
88 {
89 if (leftUnionArray[index] != rightUnionArray[index])
90 return false;
91 index++;
92 }
93 }
94 }
95 return true;
96}
97
98bool CompareStructure(const TType &leftNodeType,
99 ConstantUnion *rightUnionArray,
100 ConstantUnion *leftUnionArray)
101{
102 if (leftNodeType.isArray())
103 {
104 TType typeWithoutArrayness = leftNodeType;
105 typeWithoutArrayness.clearArrayness();
106
107 size_t arraySize = leftNodeType.getArraySize();
108
109 for (size_t i = 0; i < arraySize; ++i)
110 {
111 size_t offset = typeWithoutArrayness.getObjectSize() * i;
112 if (!CompareStruct(typeWithoutArrayness,
113 &rightUnionArray[offset],
114 &leftUnionArray[offset]))
115 {
116 return false;
117 }
118 }
119 }
120 else
121 {
122 return CompareStruct(leftNodeType, rightUnionArray, leftUnionArray);
123 }
124 return true;
125}
126
127} // namespace anonymous
128
129
130////////////////////////////////////////////////////////////////
131//
132// Member functions of the nodes used for building the tree.
133//
134////////////////////////////////////////////////////////////////
135
Olli Etuahod2a67b92014-10-21 16:42:57 +0300136void TIntermTyped::setTypePreservePrecision(const TType &t)
137{
138 TPrecision precision = getPrecision();
139 mType = t;
140 ASSERT(mType.getBasicType() != EbtBool || precision == EbpUndefined);
141 mType.setPrecision(precision);
142}
143
Jamie Madillb1a85f42014-08-19 15:23:24 -0400144#define REPLACE_IF_IS(node, type, original, replacement) \
145 if (node == original) { \
146 node = static_cast<type *>(replacement); \
147 return true; \
148 }
149
150bool TIntermLoop::replaceChildNode(
151 TIntermNode *original, TIntermNode *replacement)
152{
153 REPLACE_IF_IS(mInit, TIntermNode, original, replacement);
154 REPLACE_IF_IS(mCond, TIntermTyped, original, replacement);
155 REPLACE_IF_IS(mExpr, TIntermTyped, original, replacement);
156 REPLACE_IF_IS(mBody, TIntermNode, original, replacement);
157 return false;
158}
159
160void TIntermLoop::enqueueChildren(std::queue<TIntermNode *> *nodeQueue) const
161{
162 if (mInit)
163 {
164 nodeQueue->push(mInit);
165 }
166 if (mCond)
167 {
168 nodeQueue->push(mCond);
169 }
170 if (mExpr)
171 {
172 nodeQueue->push(mExpr);
173 }
174 if (mBody)
175 {
176 nodeQueue->push(mBody);
177 }
178}
179
180bool TIntermBranch::replaceChildNode(
181 TIntermNode *original, TIntermNode *replacement)
182{
183 REPLACE_IF_IS(mExpression, TIntermTyped, original, replacement);
184 return false;
185}
186
187void TIntermBranch::enqueueChildren(std::queue<TIntermNode *> *nodeQueue) const
188{
189 if (mExpression)
190 {
191 nodeQueue->push(mExpression);
192 }
193}
194
195bool TIntermBinary::replaceChildNode(
196 TIntermNode *original, TIntermNode *replacement)
197{
198 REPLACE_IF_IS(mLeft, TIntermTyped, original, replacement);
199 REPLACE_IF_IS(mRight, TIntermTyped, original, replacement);
200 return false;
201}
202
203void TIntermBinary::enqueueChildren(std::queue<TIntermNode *> *nodeQueue) const
204{
205 if (mLeft)
206 {
207 nodeQueue->push(mLeft);
208 }
209 if (mRight)
210 {
211 nodeQueue->push(mRight);
212 }
213}
214
215bool TIntermUnary::replaceChildNode(
216 TIntermNode *original, TIntermNode *replacement)
217{
218 REPLACE_IF_IS(mOperand, TIntermTyped, original, replacement);
219 return false;
220}
221
222void TIntermUnary::enqueueChildren(std::queue<TIntermNode *> *nodeQueue) const
223{
224 if (mOperand)
225 {
226 nodeQueue->push(mOperand);
227 }
228}
229
230bool TIntermAggregate::replaceChildNode(
231 TIntermNode *original, TIntermNode *replacement)
232{
233 for (size_t ii = 0; ii < mSequence.size(); ++ii)
234 {
235 REPLACE_IF_IS(mSequence[ii], TIntermNode, original, replacement);
236 }
237 return false;
238}
239
240void TIntermAggregate::enqueueChildren(std::queue<TIntermNode *> *nodeQueue) const
241{
242 for (size_t childIndex = 0; childIndex < mSequence.size(); childIndex++)
243 {
244 nodeQueue->push(mSequence[childIndex]);
245 }
246}
247
Olli Etuahod2a67b92014-10-21 16:42:57 +0300248void TIntermAggregate::setPrecisionFromChildren()
249{
250 if (getBasicType() == EbtBool)
251 {
252 mType.setPrecision(EbpUndefined);
253 return;
254 }
255
256 TPrecision precision = EbpUndefined;
257 TIntermSequence::iterator childIter = mSequence.begin();
258 while (childIter != mSequence.end())
259 {
260 TIntermTyped *typed = (*childIter)->getAsTyped();
261 if (typed)
262 precision = GetHigherPrecision(typed->getPrecision(), precision);
263 ++childIter;
264 }
265 mType.setPrecision(precision);
266}
267
268void TIntermAggregate::setBuiltInFunctionPrecision()
269{
270 // All built-ins returning bool should be handled as ops, not functions.
271 ASSERT(getBasicType() != EbtBool);
272
273 TPrecision precision = EbpUndefined;
274 TIntermSequence::iterator childIter = mSequence.begin();
275 while (childIter != mSequence.end())
276 {
277 TIntermTyped *typed = (*childIter)->getAsTyped();
278 // ESSL spec section 8: texture functions get their precision from the sampler.
279 if (typed && IsSampler(typed->getBasicType()))
280 {
281 precision = typed->getPrecision();
282 break;
283 }
284 ++childIter;
285 }
286 // ESSL 3.0 spec section 8: textureSize always gets highp precision.
287 // All other functions that take a sampler are assumed to be texture functions.
288 if (mName.find("textureSize") == 0)
289 mType.setPrecision(EbpHigh);
290 else
291 mType.setPrecision(precision);
292}
293
Jamie Madillb1a85f42014-08-19 15:23:24 -0400294bool TIntermSelection::replaceChildNode(
295 TIntermNode *original, TIntermNode *replacement)
296{
297 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
298 REPLACE_IF_IS(mTrueBlock, TIntermNode, original, replacement);
299 REPLACE_IF_IS(mFalseBlock, TIntermNode, original, replacement);
300 return false;
301}
302
303void TIntermSelection::enqueueChildren(std::queue<TIntermNode *> *nodeQueue) const
304{
305 if (mCondition)
306 {
307 nodeQueue->push(mCondition);
308 }
309 if (mTrueBlock)
310 {
311 nodeQueue->push(mTrueBlock);
312 }
313 if (mFalseBlock)
314 {
315 nodeQueue->push(mFalseBlock);
316 }
317}
318
319//
320// Say whether or not an operation node changes the value of a variable.
321//
322bool TIntermOperator::isAssignment() const
323{
324 switch (mOp)
325 {
326 case EOpPostIncrement:
327 case EOpPostDecrement:
328 case EOpPreIncrement:
329 case EOpPreDecrement:
330 case EOpAssign:
331 case EOpAddAssign:
332 case EOpSubAssign:
333 case EOpMulAssign:
334 case EOpVectorTimesMatrixAssign:
335 case EOpVectorTimesScalarAssign:
336 case EOpMatrixTimesScalarAssign:
337 case EOpMatrixTimesMatrixAssign:
338 case EOpDivAssign:
339 return true;
340 default:
341 return false;
342 }
343}
344
345//
346// returns true if the operator is for one of the constructors
347//
348bool TIntermOperator::isConstructor() const
349{
350 switch (mOp)
351 {
352 case EOpConstructVec2:
353 case EOpConstructVec3:
354 case EOpConstructVec4:
355 case EOpConstructMat2:
356 case EOpConstructMat3:
357 case EOpConstructMat4:
358 case EOpConstructFloat:
359 case EOpConstructIVec2:
360 case EOpConstructIVec3:
361 case EOpConstructIVec4:
362 case EOpConstructInt:
363 case EOpConstructUVec2:
364 case EOpConstructUVec3:
365 case EOpConstructUVec4:
366 case EOpConstructUInt:
367 case EOpConstructBVec2:
368 case EOpConstructBVec3:
369 case EOpConstructBVec4:
370 case EOpConstructBool:
371 case EOpConstructStruct:
372 return true;
373 default:
374 return false;
375 }
376}
377
378//
379// Make sure the type of a unary operator is appropriate for its
380// combination of operation and operand type.
381//
382// Returns false in nothing makes sense.
383//
384bool TIntermUnary::promote(TInfoSink &)
385{
386 switch (mOp)
387 {
388 case EOpLogicalNot:
389 if (mOperand->getBasicType() != EbtBool)
390 return false;
391 break;
392 case EOpNegative:
Zhenyao Mode1e00e2014-10-09 16:55:32 -0700393 case EOpPositive:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400394 case EOpPostIncrement:
395 case EOpPostDecrement:
396 case EOpPreIncrement:
397 case EOpPreDecrement:
398 if (mOperand->getBasicType() == EbtBool)
399 return false;
400 break;
401
402 // operators for built-ins are already type checked against their prototype
403 case EOpAny:
404 case EOpAll:
405 case EOpVectorLogicalNot:
406 return true;
407
408 default:
409 if (mOperand->getBasicType() != EbtFloat)
410 return false;
411 }
412
413 setType(mOperand->getType());
414 mType.setQualifier(EvqTemporary);
415
416 return true;
417}
418
419//
420// Establishes the type of the resultant operation, as well as
421// makes the operator the correct one for the operands.
422//
423// Returns false if operator can't work on operands.
424//
425bool TIntermBinary::promote(TInfoSink &infoSink)
426{
427 // This function only handles scalars, vectors, and matrices.
428 if (mLeft->isArray() || mRight->isArray())
429 {
430 infoSink.info.message(EPrefixInternalError, getLine(),
431 "Invalid operation for arrays");
432 return false;
433 }
434
435 // GLSL ES 2.0 does not support implicit type casting.
436 // So the basic type should always match.
437 if (mLeft->getBasicType() != mRight->getBasicType())
438 {
439 return false;
440 }
441
442 //
443 // Base assumption: just make the type the same as the left
444 // operand. Then only deviations from this need be coded.
445 //
446 setType(mLeft->getType());
447
448 // The result gets promoted to the highest precision.
449 TPrecision higherPrecision = GetHigherPrecision(
450 mLeft->getPrecision(), mRight->getPrecision());
451 getTypePointer()->setPrecision(higherPrecision);
452
453 // Binary operations results in temporary variables unless both
454 // operands are const.
455 if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst)
456 {
457 getTypePointer()->setQualifier(EvqTemporary);
458 }
459
460 const int nominalSize =
461 std::max(mLeft->getNominalSize(), mRight->getNominalSize());
462
463 //
464 // All scalars or structs. Code after this test assumes this case is removed!
465 //
466 if (nominalSize == 1)
467 {
468 switch (mOp)
469 {
470 //
471 // Promote to conditional
472 //
473 case EOpEqual:
474 case EOpNotEqual:
475 case EOpLessThan:
476 case EOpGreaterThan:
477 case EOpLessThanEqual:
478 case EOpGreaterThanEqual:
479 setType(TType(EbtBool, EbpUndefined));
480 break;
481
482 //
483 // And and Or operate on conditionals
484 //
485 case EOpLogicalAnd:
486 case EOpLogicalOr:
487 // Both operands must be of type bool.
488 if (mLeft->getBasicType() != EbtBool || mRight->getBasicType() != EbtBool)
489 {
490 return false;
491 }
492 setType(TType(EbtBool, EbpUndefined));
493 break;
494
495 default:
496 break;
497 }
498 return true;
499 }
500
501 // If we reach here, at least one of the operands is vector or matrix.
502 // The other operand could be a scalar, vector, or matrix.
503 // Can these two operands be combined?
504 //
505 TBasicType basicType = mLeft->getBasicType();
506 switch (mOp)
507 {
508 case EOpMul:
509 if (!mLeft->isMatrix() && mRight->isMatrix())
510 {
511 if (mLeft->isVector())
512 {
513 mOp = EOpVectorTimesMatrix;
514 setType(TType(basicType, higherPrecision, EvqTemporary,
515 mRight->getCols(), 1));
516 }
517 else
518 {
519 mOp = EOpMatrixTimesScalar;
520 setType(TType(basicType, higherPrecision, EvqTemporary,
521 mRight->getCols(), mRight->getRows()));
522 }
523 }
524 else if (mLeft->isMatrix() && !mRight->isMatrix())
525 {
526 if (mRight->isVector())
527 {
528 mOp = EOpMatrixTimesVector;
529 setType(TType(basicType, higherPrecision, EvqTemporary,
530 mLeft->getRows(), 1));
531 }
532 else
533 {
534 mOp = EOpMatrixTimesScalar;
535 }
536 }
537 else if (mLeft->isMatrix() && mRight->isMatrix())
538 {
539 mOp = EOpMatrixTimesMatrix;
540 setType(TType(basicType, higherPrecision, EvqTemporary,
541 mRight->getCols(), mLeft->getRows()));
542 }
543 else if (!mLeft->isMatrix() && !mRight->isMatrix())
544 {
545 if (mLeft->isVector() && mRight->isVector())
546 {
547 // leave as component product
548 }
549 else if (mLeft->isVector() || mRight->isVector())
550 {
551 mOp = EOpVectorTimesScalar;
552 setType(TType(basicType, higherPrecision, EvqTemporary,
553 nominalSize, 1));
554 }
555 }
556 else
557 {
558 infoSink.info.message(EPrefixInternalError, getLine(),
559 "Missing elses");
560 return false;
561 }
562
563 if (!ValidateMultiplication(mOp, mLeft->getType(), mRight->getType()))
564 {
565 return false;
566 }
567 break;
568
569 case EOpMulAssign:
570 if (!mLeft->isMatrix() && mRight->isMatrix())
571 {
572 if (mLeft->isVector())
573 {
574 mOp = EOpVectorTimesMatrixAssign;
575 }
576 else
577 {
578 return false;
579 }
580 }
581 else if (mLeft->isMatrix() && !mRight->isMatrix())
582 {
583 if (mRight->isVector())
584 {
585 return false;
586 }
587 else
588 {
589 mOp = EOpMatrixTimesScalarAssign;
590 }
591 }
592 else if (mLeft->isMatrix() && mRight->isMatrix())
593 {
594 mOp = EOpMatrixTimesMatrixAssign;
595 setType(TType(basicType, higherPrecision, EvqTemporary,
596 mRight->getCols(), mLeft->getRows()));
597 }
598 else if (!mLeft->isMatrix() && !mRight->isMatrix())
599 {
600 if (mLeft->isVector() && mRight->isVector())
601 {
602 // leave as component product
603 }
604 else if (mLeft->isVector() || mRight->isVector())
605 {
606 if (!mLeft->isVector())
607 return false;
608 mOp = EOpVectorTimesScalarAssign;
609 setType(TType(basicType, higherPrecision, EvqTemporary,
610 mLeft->getNominalSize(), 1));
611 }
612 }
613 else
614 {
615 infoSink.info.message(EPrefixInternalError, getLine(),
616 "Missing elses");
617 return false;
618 }
619
620 if (!ValidateMultiplication(mOp, mLeft->getType(), mRight->getType()))
621 {
622 return false;
623 }
624 break;
625
626 case EOpAssign:
627 case EOpInitialize:
628 case EOpAdd:
629 case EOpSub:
630 case EOpDiv:
631 case EOpAddAssign:
632 case EOpSubAssign:
633 case EOpDivAssign:
634 if ((mLeft->isMatrix() && mRight->isVector()) ||
635 (mLeft->isVector() && mRight->isMatrix()))
636 {
637 return false;
638 }
639
640 // Are the sizes compatible?
641 if (mLeft->getNominalSize() != mRight->getNominalSize() ||
642 mLeft->getSecondarySize() != mRight->getSecondarySize())
643 {
644 // If the nominal size of operands do not match:
645 // One of them must be scalar.
646 if (!mLeft->isScalar() && !mRight->isScalar())
647 return false;
648
649 // Operator cannot be of type pure assignment.
650 if (mOp == EOpAssign || mOp == EOpInitialize)
651 return false;
652 }
653
654 {
655 const int secondarySize = std::max(
656 mLeft->getSecondarySize(), mRight->getSecondarySize());
657 setType(TType(basicType, higherPrecision, EvqTemporary,
658 nominalSize, secondarySize));
659 }
660 break;
661
662 case EOpEqual:
663 case EOpNotEqual:
664 case EOpLessThan:
665 case EOpGreaterThan:
666 case EOpLessThanEqual:
667 case EOpGreaterThanEqual:
668 if ((mLeft->getNominalSize() != mRight->getNominalSize()) ||
669 (mLeft->getSecondarySize() != mRight->getSecondarySize()))
670 {
671 return false;
672 }
673 setType(TType(EbtBool, EbpUndefined));
674 break;
675
676 default:
677 return false;
678 }
679 return true;
680}
681
682//
683// The fold functions see if an operation on a constant can be done in place,
684// without generating run-time code.
685//
686// Returns the node to keep using, which may or may not be the node passed in.
687//
688TIntermTyped *TIntermConstantUnion::fold(
689 TOperator op, TIntermTyped *constantNode, TInfoSink &infoSink)
690{
691 ConstantUnion *unionArray = getUnionArrayPointer();
692
693 if (!unionArray)
694 return NULL;
695
696 size_t objectSize = getType().getObjectSize();
697
698 if (constantNode)
699 {
700 // binary operations
701 TIntermConstantUnion *node = constantNode->getAsConstantUnion();
702 ConstantUnion *rightUnionArray = node->getUnionArrayPointer();
703 TType returnType = getType();
704
705 if (!rightUnionArray)
706 return NULL;
707
708 // for a case like float f = 1.2 + vec4(2,3,4,5);
709 if (constantNode->getType().getObjectSize() == 1 && objectSize > 1)
710 {
711 rightUnionArray = new ConstantUnion[objectSize];
712 for (size_t i = 0; i < objectSize; ++i)
713 {
714 rightUnionArray[i] = *node->getUnionArrayPointer();
715 }
716 returnType = getType();
717 }
718 else if (constantNode->getType().getObjectSize() > 1 && objectSize == 1)
719 {
720 // for a case like float f = vec4(2,3,4,5) + 1.2;
721 unionArray = new ConstantUnion[constantNode->getType().getObjectSize()];
722 for (size_t i = 0; i < constantNode->getType().getObjectSize(); ++i)
723 {
724 unionArray[i] = *getUnionArrayPointer();
725 }
726 returnType = node->getType();
727 objectSize = constantNode->getType().getObjectSize();
728 }
729
730 ConstantUnion *tempConstArray = NULL;
731 TIntermConstantUnion *tempNode;
732
733 bool boolNodeFlag = false;
734 switch(op)
735 {
736 case EOpAdd:
737 tempConstArray = new ConstantUnion[objectSize];
738 for (size_t i = 0; i < objectSize; i++)
739 tempConstArray[i] = unionArray[i] + rightUnionArray[i];
740 break;
741 case EOpSub:
742 tempConstArray = new ConstantUnion[objectSize];
743 for (size_t i = 0; i < objectSize; i++)
744 tempConstArray[i] = unionArray[i] - rightUnionArray[i];
745 break;
746
747 case EOpMul:
748 case EOpVectorTimesScalar:
749 case EOpMatrixTimesScalar:
750 tempConstArray = new ConstantUnion[objectSize];
751 for (size_t i = 0; i < objectSize; i++)
752 tempConstArray[i] = unionArray[i] * rightUnionArray[i];
753 break;
754
755 case EOpMatrixTimesMatrix:
756 {
757 if (getType().getBasicType() != EbtFloat ||
758 node->getBasicType() != EbtFloat)
759 {
760 infoSink.info.message(
761 EPrefixInternalError, getLine(),
762 "Constant Folding cannot be done for matrix multiply");
763 return NULL;
764 }
765
766 const int leftCols = getCols();
767 const int leftRows = getRows();
768 const int rightCols = constantNode->getType().getCols();
769 const int rightRows = constantNode->getType().getRows();
770 const int resultCols = rightCols;
771 const int resultRows = leftRows;
772
773 tempConstArray = new ConstantUnion[resultCols*resultRows];
774 for (int row = 0; row < resultRows; row++)
775 {
776 for (int column = 0; column < resultCols; column++)
777 {
778 tempConstArray[resultRows * column + row].setFConst(0.0f);
779 for (int i = 0; i < leftCols; i++)
780 {
781 tempConstArray[resultRows * column + row].setFConst(
782 tempConstArray[resultRows * column + row].getFConst() +
783 unionArray[i * leftRows + row].getFConst() *
784 rightUnionArray[column * rightRows + i].getFConst());
785 }
786 }
787 }
788
789 // update return type for matrix product
790 returnType.setPrimarySize(resultCols);
791 returnType.setSecondarySize(resultRows);
792 }
793 break;
794
795 case EOpDiv:
796 {
797 tempConstArray = new ConstantUnion[objectSize];
798 for (size_t i = 0; i < objectSize; i++)
799 {
800 switch (getType().getBasicType())
801 {
802 case EbtFloat:
803 if (rightUnionArray[i] == 0.0f)
804 {
805 infoSink.info.message(
806 EPrefixWarning, getLine(),
807 "Divide by zero error during constant folding");
808 tempConstArray[i].setFConst(
809 unionArray[i].getFConst() < 0 ? -FLT_MAX : FLT_MAX);
810 }
811 else
812 {
813 tempConstArray[i].setFConst(
814 unionArray[i].getFConst() /
815 rightUnionArray[i].getFConst());
816 }
817 break;
818
819 case EbtInt:
820 if (rightUnionArray[i] == 0)
821 {
822 infoSink.info.message(
823 EPrefixWarning, getLine(),
824 "Divide by zero error during constant folding");
825 tempConstArray[i].setIConst(INT_MAX);
826 }
827 else
828 {
829 tempConstArray[i].setIConst(
830 unionArray[i].getIConst() /
831 rightUnionArray[i].getIConst());
832 }
833 break;
834
835 case EbtUInt:
836 if (rightUnionArray[i] == 0)
837 {
838 infoSink.info.message(
839 EPrefixWarning, getLine(),
840 "Divide by zero error during constant folding");
841 tempConstArray[i].setUConst(UINT_MAX);
842 }
843 else
844 {
845 tempConstArray[i].setUConst(
846 unionArray[i].getUConst() /
847 rightUnionArray[i].getUConst());
848 }
849 break;
850
851 default:
852 infoSink.info.message(
853 EPrefixInternalError, getLine(),
854 "Constant folding cannot be done for \"/\"");
855 return NULL;
856 }
857 }
858 }
859 break;
860
861 case EOpMatrixTimesVector:
862 {
863 if (node->getBasicType() != EbtFloat)
864 {
865 infoSink.info.message(
866 EPrefixInternalError, getLine(),
867 "Constant Folding cannot be done for matrix times vector");
868 return NULL;
869 }
870
871 const int matrixCols = getCols();
872 const int matrixRows = getRows();
873
874 tempConstArray = new ConstantUnion[matrixRows];
875
876 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
877 {
878 tempConstArray[matrixRow].setFConst(0.0f);
879 for (int col = 0; col < matrixCols; col++)
880 {
881 tempConstArray[matrixRow].setFConst(
882 tempConstArray[matrixRow].getFConst() +
883 unionArray[col * matrixRows + matrixRow].getFConst() *
884 rightUnionArray[col].getFConst());
885 }
886 }
887
888 returnType = node->getType();
889 returnType.setPrimarySize(matrixRows);
890
891 tempNode = new TIntermConstantUnion(tempConstArray, returnType);
892 tempNode->setLine(getLine());
893
894 return tempNode;
895 }
896
897 case EOpVectorTimesMatrix:
898 {
899 if (getType().getBasicType() != EbtFloat)
900 {
901 infoSink.info.message(
902 EPrefixInternalError, getLine(),
903 "Constant Folding cannot be done for vector times matrix");
904 return NULL;
905 }
906
907 const int matrixCols = constantNode->getType().getCols();
908 const int matrixRows = constantNode->getType().getRows();
909
910 tempConstArray = new ConstantUnion[matrixCols];
911
912 for (int matrixCol = 0; matrixCol < matrixCols; matrixCol++)
913 {
914 tempConstArray[matrixCol].setFConst(0.0f);
915 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
916 {
917 tempConstArray[matrixCol].setFConst(
918 tempConstArray[matrixCol].getFConst() +
919 unionArray[matrixRow].getFConst() *
920 rightUnionArray[matrixCol * matrixRows + matrixRow].getFConst());
921 }
922 }
923
924 returnType.setPrimarySize(matrixCols);
925 }
926 break;
927
928 case EOpLogicalAnd:
929 // this code is written for possible future use,
930 // will not get executed currently
931 {
932 tempConstArray = new ConstantUnion[objectSize];
933 for (size_t i = 0; i < objectSize; i++)
934 {
935 tempConstArray[i] = unionArray[i] && rightUnionArray[i];
936 }
937 }
938 break;
939
940 case EOpLogicalOr:
941 // this code is written for possible future use,
942 // will not get executed currently
943 {
944 tempConstArray = new ConstantUnion[objectSize];
945 for (size_t i = 0; i < objectSize; i++)
946 {
947 tempConstArray[i] = unionArray[i] || rightUnionArray[i];
948 }
949 }
950 break;
951
952 case EOpLogicalXor:
953 {
954 tempConstArray = new ConstantUnion[objectSize];
955 for (size_t i = 0; i < objectSize; i++)
956 {
957 switch (getType().getBasicType())
958 {
959 case EbtBool:
960 tempConstArray[i].setBConst(
961 unionArray[i] == rightUnionArray[i] ? false : true);
962 break;
963 default:
964 UNREACHABLE();
965 break;
966 }
967 }
968 }
969 break;
970
971 case EOpLessThan:
972 ASSERT(objectSize == 1);
973 tempConstArray = new ConstantUnion[1];
974 tempConstArray->setBConst(*unionArray < *rightUnionArray);
975 returnType = TType(EbtBool, EbpUndefined, EvqConst);
976 break;
977
978 case EOpGreaterThan:
979 ASSERT(objectSize == 1);
980 tempConstArray = new ConstantUnion[1];
981 tempConstArray->setBConst(*unionArray > *rightUnionArray);
982 returnType = TType(EbtBool, EbpUndefined, EvqConst);
983 break;
984
985 case EOpLessThanEqual:
986 {
987 ASSERT(objectSize == 1);
988 ConstantUnion constant;
989 constant.setBConst(*unionArray > *rightUnionArray);
990 tempConstArray = new ConstantUnion[1];
991 tempConstArray->setBConst(!constant.getBConst());
992 returnType = TType(EbtBool, EbpUndefined, EvqConst);
993 break;
994 }
995
996 case EOpGreaterThanEqual:
997 {
998 ASSERT(objectSize == 1);
999 ConstantUnion constant;
1000 constant.setBConst(*unionArray < *rightUnionArray);
1001 tempConstArray = new ConstantUnion[1];
1002 tempConstArray->setBConst(!constant.getBConst());
1003 returnType = TType(EbtBool, EbpUndefined, EvqConst);
1004 break;
1005 }
1006
1007 case EOpEqual:
1008 if (getType().getBasicType() == EbtStruct)
1009 {
1010 if (!CompareStructure(node->getType(),
1011 node->getUnionArrayPointer(),
1012 unionArray))
1013 {
1014 boolNodeFlag = true;
1015 }
1016 }
1017 else
1018 {
1019 for (size_t i = 0; i < objectSize; i++)
1020 {
1021 if (unionArray[i] != rightUnionArray[i])
1022 {
1023 boolNodeFlag = true;
1024 break; // break out of for loop
1025 }
1026 }
1027 }
1028
1029 tempConstArray = new ConstantUnion[1];
1030 if (!boolNodeFlag)
1031 {
1032 tempConstArray->setBConst(true);
1033 }
1034 else
1035 {
1036 tempConstArray->setBConst(false);
1037 }
1038
1039 tempNode = new TIntermConstantUnion(
1040 tempConstArray, TType(EbtBool, EbpUndefined, EvqConst));
1041 tempNode->setLine(getLine());
1042
1043 return tempNode;
1044
1045 case EOpNotEqual:
1046 if (getType().getBasicType() == EbtStruct)
1047 {
1048 if (CompareStructure(node->getType(),
1049 node->getUnionArrayPointer(),
1050 unionArray))
1051 {
1052 boolNodeFlag = true;
1053 }
1054 }
1055 else
1056 {
1057 for (size_t i = 0; i < objectSize; i++)
1058 {
1059 if (unionArray[i] == rightUnionArray[i])
1060 {
1061 boolNodeFlag = true;
1062 break; // break out of for loop
1063 }
1064 }
1065 }
1066
1067 tempConstArray = new ConstantUnion[1];
1068 if (!boolNodeFlag)
1069 {
1070 tempConstArray->setBConst(true);
1071 }
1072 else
1073 {
1074 tempConstArray->setBConst(false);
1075 }
1076
1077 tempNode = new TIntermConstantUnion(
1078 tempConstArray, TType(EbtBool, EbpUndefined, EvqConst));
1079 tempNode->setLine(getLine());
1080
1081 return tempNode;
1082
1083 default:
1084 infoSink.info.message(
1085 EPrefixInternalError, getLine(),
1086 "Invalid operator for constant folding");
1087 return NULL;
1088 }
1089 tempNode = new TIntermConstantUnion(tempConstArray, returnType);
1090 tempNode->setLine(getLine());
1091
1092 return tempNode;
1093 }
1094 else
1095 {
1096 //
1097 // Do unary operations
1098 //
1099 TIntermConstantUnion *newNode = 0;
1100 ConstantUnion* tempConstArray = new ConstantUnion[objectSize];
1101 for (size_t i = 0; i < objectSize; i++)
1102 {
1103 switch(op)
1104 {
1105 case EOpNegative:
1106 switch (getType().getBasicType())
1107 {
1108 case EbtFloat:
1109 tempConstArray[i].setFConst(-unionArray[i].getFConst());
1110 break;
1111 case EbtInt:
1112 tempConstArray[i].setIConst(-unionArray[i].getIConst());
1113 break;
1114 case EbtUInt:
1115 tempConstArray[i].setUConst(static_cast<unsigned int>(
1116 -static_cast<int>(unionArray[i].getUConst())));
1117 break;
1118 default:
1119 infoSink.info.message(
1120 EPrefixInternalError, getLine(),
1121 "Unary operation not folded into constant");
1122 return NULL;
1123 }
1124 break;
1125
Zhenyao Mode1e00e2014-10-09 16:55:32 -07001126 case EOpPositive:
1127 switch (getType().getBasicType())
1128 {
1129 case EbtFloat:
1130 tempConstArray[i].setFConst(unionArray[i].getFConst());
1131 break;
1132 case EbtInt:
1133 tempConstArray[i].setIConst(unionArray[i].getIConst());
1134 break;
1135 case EbtUInt:
1136 tempConstArray[i].setUConst(static_cast<unsigned int>(
1137 static_cast<int>(unionArray[i].getUConst())));
1138 break;
1139 default:
1140 infoSink.info.message(
1141 EPrefixInternalError, getLine(),
1142 "Unary operation not folded into constant");
1143 return NULL;
1144 }
1145 break;
1146
Jamie Madillb1a85f42014-08-19 15:23:24 -04001147 case EOpLogicalNot:
1148 // this code is written for possible future use,
1149 // will not get executed currently
1150 switch (getType().getBasicType())
1151 {
1152 case EbtBool:
1153 tempConstArray[i].setBConst(!unionArray[i].getBConst());
1154 break;
1155 default:
1156 infoSink.info.message(
1157 EPrefixInternalError, getLine(),
1158 "Unary operation not folded into constant");
1159 return NULL;
1160 }
1161 break;
1162
1163 default:
1164 return NULL;
1165 }
1166 }
1167 newNode = new TIntermConstantUnion(tempConstArray, getType());
1168 newNode->setLine(getLine());
1169 return newNode;
1170 }
1171}
1172
1173// static
1174TString TIntermTraverser::hash(const TString &name, ShHashFunction64 hashFunction)
1175{
1176 if (hashFunction == NULL || name.empty())
1177 return name;
1178 khronos_uint64_t number = (*hashFunction)(name.c_str(), name.length());
1179 TStringStream stream;
1180 stream << HASHED_NAME_PREFIX << std::hex << number;
1181 TString hashedName = stream.str();
1182 return hashedName;
1183}