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