Upstream version 11.40.277.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 void 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
144 #define REPLACE_IF_IS(node, type, original, replacement) \
145     if (node == original) { \
146         node = static_cast<type *>(replacement); \
147         return true; \
148     }
149
150 bool 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
160 void 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
180 bool TIntermBranch::replaceChildNode(
181     TIntermNode *original, TIntermNode *replacement)
182 {
183     REPLACE_IF_IS(mExpression, TIntermTyped, original, replacement);
184     return false;
185 }
186
187 void TIntermBranch::enqueueChildren(std::queue<TIntermNode *> *nodeQueue) const
188 {
189     if (mExpression)
190     {
191         nodeQueue->push(mExpression);
192     }
193 }
194
195 bool 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
203 void 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
215 bool TIntermUnary::replaceChildNode(
216     TIntermNode *original, TIntermNode *replacement)
217 {
218     REPLACE_IF_IS(mOperand, TIntermTyped, original, replacement);
219     return false;
220 }
221
222 void TIntermUnary::enqueueChildren(std::queue<TIntermNode *> *nodeQueue) const
223 {
224     if (mOperand)
225     {
226         nodeQueue->push(mOperand);
227     }
228 }
229
230 bool 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
240 void 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
248 void 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
268 void 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
294 bool 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
303 void 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 //
322 bool 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 //
348 bool 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 //
384 bool TIntermUnary::promote(TInfoSink &)
385 {
386     switch (mOp)
387     {
388       case EOpLogicalNot:
389         if (mOperand->getBasicType() != EbtBool)
390             return false;
391         break;
392       case EOpNegative:
393       case EOpPositive:
394       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 //
425 bool 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 //
688 TIntermTyped *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
1126               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
1147               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
1174 TString 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 }