Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / third_party / angle / src / compiler / translator / Intermediate.cpp
1 //
2 // Copyright (c) 2002-2013 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/localintermediate.h"
17 #include "compiler/translator/QualifierAlive.h"
18 #include "compiler/translator/RemoveTree.h"
19
20 bool CompareStructure(const TType& leftNodeType, ConstantUnion* rightUnionArray, ConstantUnion* leftUnionArray);
21
22 static TPrecision GetHigherPrecision(TPrecision left, TPrecision right)
23 {
24     return left > right ? left : right;
25 }
26
27 const char* getOperatorString(TOperator op)
28 {
29     switch (op) {
30       case EOpInitialize: return "=";
31       case EOpAssign: return "=";
32       case EOpAddAssign: return "+=";
33       case EOpSubAssign: return "-=";
34       case EOpDivAssign: return "/=";
35
36       // Fall-through.
37       case EOpMulAssign: 
38       case EOpVectorTimesMatrixAssign:
39       case EOpVectorTimesScalarAssign:
40       case EOpMatrixTimesScalarAssign:
41       case EOpMatrixTimesMatrixAssign: return "*=";
42
43       // Fall-through.
44       case EOpIndexDirect:
45       case EOpIndexIndirect: return "[]";
46
47       case EOpIndexDirectStruct: return ".";
48       case EOpVectorSwizzle: return ".";
49       case EOpAdd: return "+";
50       case EOpSub: return "-";
51       case EOpMul: return "*";
52       case EOpDiv: return "/";
53       case EOpMod: UNIMPLEMENTED(); break;
54       case EOpEqual: return "==";
55       case EOpNotEqual: return "!=";
56       case EOpLessThan: return "<";
57       case EOpGreaterThan: return ">";
58       case EOpLessThanEqual: return "<=";
59       case EOpGreaterThanEqual: return ">=";
60
61       // Fall-through.
62       case EOpVectorTimesScalar:
63       case EOpVectorTimesMatrix:
64       case EOpMatrixTimesVector:
65       case EOpMatrixTimesScalar:
66       case EOpMatrixTimesMatrix: return "*";
67
68       case EOpLogicalOr: return "||";
69       case EOpLogicalXor: return "^^";
70       case EOpLogicalAnd: return "&&";
71       case EOpNegative: return "-";
72       case EOpVectorLogicalNot: return "not";
73       case EOpLogicalNot: return "!";
74       case EOpPostIncrement: return "++";
75       case EOpPostDecrement: return "--";
76       case EOpPreIncrement: return "++";
77       case EOpPreDecrement: return "--";
78
79       // Fall-through.
80       case EOpConvIntToBool:
81       case EOpConvFloatToBool: return "bool";
82  
83       // Fall-through.
84       case EOpConvBoolToFloat:
85       case EOpConvIntToFloat: return "float";
86  
87       // Fall-through.
88       case EOpConvFloatToInt:
89       case EOpConvBoolToInt: return "int";
90
91       case EOpRadians: return "radians";
92       case EOpDegrees: return "degrees";
93       case EOpSin: return "sin";
94       case EOpCos: return "cos";
95       case EOpTan: return "tan";
96       case EOpAsin: return "asin";
97       case EOpAcos: return "acos";
98       case EOpAtan: return "atan";
99       case EOpExp: return "exp";
100       case EOpLog: return "log";
101       case EOpExp2: return "exp2";
102       case EOpLog2: return "log2";
103       case EOpSqrt: return "sqrt";
104       case EOpInverseSqrt: return "inversesqrt";
105       case EOpAbs: return "abs";
106       case EOpSign: return "sign";
107       case EOpFloor: return "floor";
108       case EOpCeil: return "ceil";
109       case EOpFract: return "fract";
110       case EOpLength: return "length";
111       case EOpNormalize: return "normalize";
112       case EOpDFdx: return "dFdx";
113       case EOpDFdy: return "dFdy";
114       case EOpFwidth: return "fwidth";
115       case EOpAny: return "any";
116       case EOpAll: return "all";
117
118       default: break;
119     }
120     return "";
121 }
122
123 ////////////////////////////////////////////////////////////////////////////
124 //
125 // First set of functions are to help build the intermediate representation.
126 // These functions are not member functions of the nodes.
127 // They are called from parser productions.
128 //
129 /////////////////////////////////////////////////////////////////////////////
130
131 //
132 // Add a terminal node for an identifier in an expression.
133 //
134 // Returns the added node.
135 //
136 TIntermSymbol* TIntermediate::addSymbol(int id, const TString& name, const TType& type, const TSourceLoc& line)
137 {
138     TIntermSymbol* node = new TIntermSymbol(id, name, type);
139     node->setLine(line);
140
141     return node;
142 }
143
144 //
145 // Connect two nodes with a new parent that does a binary operation on the nodes.
146 //
147 // Returns the added node.
148 //
149 TIntermTyped* TIntermediate::addBinaryMath(TOperator op, TIntermTyped* left, TIntermTyped* right, const TSourceLoc& line, TSymbolTable& symbolTable)
150 {
151     switch (op) {
152         case EOpEqual:
153         case EOpNotEqual:
154             if (left->isArray())
155                 return 0;
156             break;
157         case EOpLessThan:
158         case EOpGreaterThan:
159         case EOpLessThanEqual:
160         case EOpGreaterThanEqual:
161             if (left->isMatrix() || left->isArray() || left->isVector() || left->getBasicType() == EbtStruct) {
162                 return 0;
163             }
164             break;
165         case EOpLogicalOr:
166         case EOpLogicalXor:
167         case EOpLogicalAnd:
168             if (left->getBasicType() != EbtBool || left->isMatrix() || left->isArray() || left->isVector()) {
169                 return 0;
170             }
171             break;
172         case EOpAdd:
173         case EOpSub:
174         case EOpDiv:
175         case EOpMul:
176             if (left->getBasicType() == EbtStruct || left->getBasicType() == EbtBool)
177                 return 0;
178         default: break;
179     }
180
181     //
182     // First try converting the children to compatible types.
183     //
184     if (left->getType().getStruct() && right->getType().getStruct()) {
185         if (left->getType() != right->getType())
186             return 0;
187     } else {
188         TIntermTyped* child = addConversion(op, left->getType(), right);
189         if (child)
190             right = child;
191         else {
192             child = addConversion(op, right->getType(), left);
193             if (child)
194                 left = child;
195             else
196                 return 0;
197         }
198     }
199
200     //
201     // Need a new node holding things together then.  Make
202     // one and promote it to the right type.
203     //
204     TIntermBinary* node = new TIntermBinary(op);
205     node->setLine(line);
206
207     node->setLeft(left);
208     node->setRight(right);
209     if (!node->promote(infoSink))
210         return 0;
211
212     //
213     // See if we can fold constants.
214     //
215     TIntermConstantUnion *leftTempConstant = left->getAsConstantUnion();
216     TIntermConstantUnion *rightTempConstant = right->getAsConstantUnion();
217     if (leftTempConstant && rightTempConstant) {
218         TIntermTyped *typedReturnNode = leftTempConstant->fold(node->getOp(), rightTempConstant, infoSink);
219
220         if (typedReturnNode)
221             return typedReturnNode;
222     }
223
224     return node;
225 }
226
227 //
228 // Connect two nodes through an assignment.
229 //
230 // Returns the added node.
231 //
232 TIntermTyped* TIntermediate::addAssign(TOperator op, TIntermTyped* left, TIntermTyped* right, const TSourceLoc& line)
233 {
234     //
235     // Like adding binary math, except the conversion can only go
236     // from right to left.
237     //
238     TIntermBinary* node = new TIntermBinary(op);
239     node->setLine(line);
240
241     TIntermTyped* child = addConversion(op, left->getType(), right);
242     if (child == 0)
243         return 0;
244
245     node->setLeft(left);
246     node->setRight(child);
247     if (! node->promote(infoSink))
248         return 0;
249
250     return node;
251 }
252
253 //
254 // Connect two nodes through an index operator, where the left node is the base
255 // of an array or struct, and the right node is a direct or indirect offset.
256 //
257 // Returns the added node.
258 // The caller should set the type of the returned node.
259 //
260 TIntermTyped* TIntermediate::addIndex(TOperator op, TIntermTyped* base, TIntermTyped* index, const TSourceLoc& line)
261 {
262     TIntermBinary* node = new TIntermBinary(op);
263     node->setLine(line);
264     node->setLeft(base);
265     node->setRight(index);
266
267     // caller should set the type
268
269     return node;
270 }
271
272 //
273 // Add one node as the parent of another that it operates on.
274 //
275 // Returns the added node.
276 //
277 TIntermTyped* TIntermediate::addUnaryMath(TOperator op, TIntermNode* childNode, const TSourceLoc& line, TSymbolTable& symbolTable)
278 {
279     TIntermUnary* node;
280     TIntermTyped* child = childNode->getAsTyped();
281
282     if (child == 0) {
283         infoSink.info.message(EPrefixInternalError, line, "Bad type in AddUnaryMath");
284         return 0;
285     }
286
287     switch (op) {
288         case EOpLogicalNot:
289             if (child->getType().getBasicType() != EbtBool || child->getType().isMatrix() || child->getType().isArray() || child->getType().isVector()) {
290                 return 0;
291             }
292             break;
293
294         case EOpPostIncrement:
295         case EOpPreIncrement:
296         case EOpPostDecrement:
297         case EOpPreDecrement:
298         case EOpNegative:
299             if (child->getType().getBasicType() == EbtStruct || child->getType().isArray())
300                 return 0;
301         default: break;
302     }
303
304     //
305     // Do we need to promote the operand?
306     //
307     // Note: Implicit promotions were removed from the language.
308     //
309     TBasicType newType = EbtVoid;
310     switch (op) {
311         case EOpConstructInt:   newType = EbtInt;   break;
312         case EOpConstructBool:  newType = EbtBool;  break;
313         case EOpConstructFloat: newType = EbtFloat; break;
314         default: break;
315     }
316
317     if (newType != EbtVoid) {
318         child = addConversion(op, TType(newType, child->getPrecision(), EvqTemporary,
319             child->getNominalSize(),
320             child->isMatrix(),
321             child->isArray()),
322             child);
323         if (child == 0)
324             return 0;
325     }
326
327     //
328     // For constructors, we are now done, it's all in the conversion.
329     //
330     switch (op) {
331         case EOpConstructInt:
332         case EOpConstructBool:
333         case EOpConstructFloat:
334             return child;
335         default: break;
336     }
337
338     TIntermConstantUnion *childTempConstant = 0;
339     if (child->getAsConstantUnion())
340         childTempConstant = child->getAsConstantUnion();
341
342     //
343     // Make a new node for the operator.
344     //
345     node = new TIntermUnary(op);
346     node->setLine(line);
347     node->setOperand(child);
348
349     if (! node->promote(infoSink))
350         return 0;
351
352     if (childTempConstant)  {
353         TIntermTyped* newChild = childTempConstant->fold(op, 0, infoSink);
354
355         if (newChild)
356             return newChild;
357     }
358
359     return node;
360 }
361
362 //
363 // This is the safe way to change the operator on an aggregate, as it
364 // does lots of error checking and fixing.  Especially for establishing
365 // a function call's operation on it's set of parameters.  Sequences
366 // of instructions are also aggregates, but they just direnctly set
367 // their operator to EOpSequence.
368 //
369 // Returns an aggregate node, which could be the one passed in if
370 // it was already an aggregate but no operator was set.
371 //
372 TIntermAggregate* TIntermediate::setAggregateOperator(TIntermNode* node, TOperator op, const TSourceLoc& line)
373 {
374     TIntermAggregate* aggNode;
375
376     //
377     // Make sure we have an aggregate.  If not turn it into one.
378     //
379     if (node) {
380         aggNode = node->getAsAggregate();
381         if (aggNode == 0 || aggNode->getOp() != EOpNull) {
382             //
383             // Make an aggregate containing this node.
384             //
385             aggNode = new TIntermAggregate();
386             aggNode->getSequence().push_back(node);
387         }
388     } else
389         aggNode = new TIntermAggregate();
390
391     //
392     // Set the operator.
393     //
394     aggNode->setOp(op);
395     aggNode->setLine(line);
396
397     return aggNode;
398 }
399
400 //
401 // Convert one type to another.
402 //
403 // Returns the node representing the conversion, which could be the same
404 // node passed in if no conversion was needed.
405 //
406 // Return 0 if a conversion can't be done.
407 //
408 TIntermTyped* TIntermediate::addConversion(TOperator op, const TType& type, TIntermTyped* node)
409 {
410     //
411     // Does the base type allow operation?
412     //
413     switch (node->getBasicType()) {
414         case EbtVoid:
415         case EbtSampler2D:
416         case EbtSamplerCube:
417             return 0;
418         default: break;
419     }
420
421     //
422     // Otherwise, if types are identical, no problem
423     //
424     if (type == node->getType())
425         return node;
426
427     //
428     // If one's a structure, then no conversions.
429     //
430     if (type.getStruct() || node->getType().getStruct())
431         return 0;
432
433     //
434     // If one's an array, then no conversions.
435     //
436     if (type.isArray() || node->getType().isArray())
437         return 0;
438
439     TBasicType promoteTo;
440
441     switch (op) {
442         //
443         // Explicit conversions
444         //
445         case EOpConstructBool:
446             promoteTo = EbtBool;
447             break;
448         case EOpConstructFloat:
449             promoteTo = EbtFloat;
450             break;
451         case EOpConstructInt:
452             promoteTo = EbtInt;
453             break;
454         default:
455             //
456             // implicit conversions were removed from the language.
457             //
458             if (type.getBasicType() != node->getType().getBasicType())
459                 return 0;
460             //
461             // Size and structure could still differ, but that's
462             // handled by operator promotion.
463             //
464             return node;
465     }
466
467     if (node->getAsConstantUnion()) {
468
469         return (promoteConstantUnion(promoteTo, node->getAsConstantUnion()));
470     } else {
471
472         //
473         // Add a new newNode for the conversion.
474         //
475         TIntermUnary* newNode = 0;
476
477         TOperator newOp = EOpNull;
478         switch (promoteTo) {
479             case EbtFloat:
480                 switch (node->getBasicType()) {
481                     case EbtInt:   newOp = EOpConvIntToFloat;  break;
482                     case EbtBool:  newOp = EOpConvBoolToFloat; break;
483                     default:
484                         infoSink.info.message(EPrefixInternalError, node->getLine(), "Bad promotion node");
485                         return 0;
486                 }
487                 break;
488             case EbtBool:
489                 switch (node->getBasicType()) {
490                     case EbtInt:   newOp = EOpConvIntToBool;   break;
491                     case EbtFloat: newOp = EOpConvFloatToBool; break;
492                     default:
493                         infoSink.info.message(EPrefixInternalError, node->getLine(), "Bad promotion node");
494                         return 0;
495                 }
496                 break;
497             case EbtInt:
498                 switch (node->getBasicType()) {
499                     case EbtBool:   newOp = EOpConvBoolToInt;  break;
500                     case EbtFloat:  newOp = EOpConvFloatToInt; break;
501                     default:
502                         infoSink.info.message(EPrefixInternalError, node->getLine(), "Bad promotion node");
503                         return 0;
504                 }
505                 break;
506             default:
507                 infoSink.info.message(EPrefixInternalError, node->getLine(), "Bad promotion type");
508                 return 0;
509         }
510
511         TType type(promoteTo, node->getPrecision(), EvqTemporary, node->getNominalSize(), node->isMatrix(), node->isArray());
512         newNode = new TIntermUnary(newOp, type);
513         newNode->setLine(node->getLine());
514         newNode->setOperand(node);
515
516         return newNode;
517     }
518 }
519
520 //
521 // Safe way to combine two nodes into an aggregate.  Works with null pointers,
522 // a node that's not a aggregate yet, etc.
523 //
524 // Returns the resulting aggregate, unless 0 was passed in for
525 // both existing nodes.
526 //
527 TIntermAggregate* TIntermediate::growAggregate(TIntermNode* left, TIntermNode* right, const TSourceLoc& line)
528 {
529     if (left == 0 && right == 0)
530         return 0;
531
532     TIntermAggregate* aggNode = 0;
533     if (left)
534         aggNode = left->getAsAggregate();
535     if (!aggNode || aggNode->getOp() != EOpNull) {
536         aggNode = new TIntermAggregate;
537         if (left)
538             aggNode->getSequence().push_back(left);
539     }
540
541     if (right)
542         aggNode->getSequence().push_back(right);
543
544     aggNode->setLine(line);
545
546     return aggNode;
547 }
548
549 //
550 // Turn an existing node into an aggregate.
551 //
552 // Returns an aggregate, unless 0 was passed in for the existing node.
553 //
554 TIntermAggregate* TIntermediate::makeAggregate(TIntermNode* node, const TSourceLoc& line)
555 {
556     if (node == 0)
557         return 0;
558
559     TIntermAggregate* aggNode = new TIntermAggregate;
560     aggNode->getSequence().push_back(node);
561     aggNode->setLine(line);
562
563     return aggNode;
564 }
565
566 //
567 // For "if" test nodes.  There are three children; a condition,
568 // a true path, and a false path.  The two paths are in the
569 // nodePair.
570 //
571 // Returns the selection node created.
572 //
573 TIntermNode* TIntermediate::addSelection(TIntermTyped* cond, TIntermNodePair nodePair, const TSourceLoc& line)
574 {
575     //
576     // For compile time constant selections, prune the code and
577     // test now.
578     //
579
580     if (cond->getAsTyped() && cond->getAsTyped()->getAsConstantUnion()) {
581         if (cond->getAsConstantUnion()->getBConst(0) == true)
582             return nodePair.node1 ? setAggregateOperator(nodePair.node1, EOpSequence, nodePair.node1->getLine()) : NULL;
583         else
584             return nodePair.node2 ? setAggregateOperator(nodePair.node2, EOpSequence, nodePair.node2->getLine()) : NULL;
585     }
586
587     TIntermSelection* node = new TIntermSelection(cond, nodePair.node1, nodePair.node2);
588     node->setLine(line);
589
590     return node;
591 }
592
593
594 TIntermTyped* TIntermediate::addComma(TIntermTyped* left, TIntermTyped* right, const TSourceLoc& line)
595 {
596     if (left->getType().getQualifier() == EvqConst && right->getType().getQualifier() == EvqConst) {
597         return right;
598     } else {
599         TIntermTyped *commaAggregate = growAggregate(left, right, line);
600         commaAggregate->getAsAggregate()->setOp(EOpComma);
601         commaAggregate->setType(right->getType());
602         commaAggregate->getTypePointer()->setQualifier(EvqTemporary);
603         return commaAggregate;
604     }
605 }
606
607 //
608 // For "?:" test nodes.  There are three children; a condition,
609 // a true path, and a false path.  The two paths are specified
610 // as separate parameters.
611 //
612 // Returns the selection node created, or 0 if one could not be.
613 //
614 TIntermTyped* TIntermediate::addSelection(TIntermTyped* cond, TIntermTyped* trueBlock, TIntermTyped* falseBlock, const TSourceLoc& line)
615 {
616     //
617     // Get compatible types.
618     //
619     TIntermTyped* child = addConversion(EOpSequence, trueBlock->getType(), falseBlock);
620     if (child)
621         falseBlock = child;
622     else {
623         child = addConversion(EOpSequence, falseBlock->getType(), trueBlock);
624         if (child)
625             trueBlock = child;
626         else
627             return 0;
628     }
629
630     //
631     // See if all the operands are constant, then fold it otherwise not.
632     //
633
634     if (cond->getAsConstantUnion() && trueBlock->getAsConstantUnion() && falseBlock->getAsConstantUnion()) {
635         if (cond->getAsConstantUnion()->getBConst(0))
636             return trueBlock;
637         else
638             return falseBlock;
639     }
640
641     //
642     // Make a selection node.
643     //
644     TIntermSelection* node = new TIntermSelection(cond, trueBlock, falseBlock, trueBlock->getType());
645     node->getTypePointer()->setQualifier(EvqTemporary);
646     node->setLine(line);
647
648     return node;
649 }
650
651 //
652 // Constant terminal nodes.  Has a union that contains bool, float or int constants
653 //
654 // Returns the constant union node created.
655 //
656
657 TIntermConstantUnion* TIntermediate::addConstantUnion(ConstantUnion* unionArrayPointer, const TType& t, const TSourceLoc& line)
658 {
659     TIntermConstantUnion* node = new TIntermConstantUnion(unionArrayPointer, t);
660     node->setLine(line);
661
662     return node;
663 }
664
665 TIntermTyped* TIntermediate::addSwizzle(TVectorFields& fields, const TSourceLoc& line)
666 {
667
668     TIntermAggregate* node = new TIntermAggregate(EOpSequence);
669
670     node->setLine(line);
671     TIntermConstantUnion* constIntNode;
672     TIntermSequence &sequenceVector = node->getSequence();
673     ConstantUnion* unionArray;
674
675     for (int i = 0; i < fields.num; i++) {
676         unionArray = new ConstantUnion[1];
677         unionArray->setIConst(fields.offsets[i]);
678         constIntNode = addConstantUnion(unionArray, TType(EbtInt, EbpUndefined, EvqConst), line);
679         sequenceVector.push_back(constIntNode);
680     }
681
682     return node;
683 }
684
685 //
686 // Create loop nodes.
687 //
688 TIntermNode* TIntermediate::addLoop(TLoopType type, TIntermNode* init, TIntermTyped* cond, TIntermTyped* expr, TIntermNode* body, const TSourceLoc& line)
689 {
690     TIntermNode* node = new TIntermLoop(type, init, cond, expr, body);
691     node->setLine(line);
692
693     return node;
694 }
695
696 //
697 // Add branches.
698 //
699 TIntermBranch* TIntermediate::addBranch(TOperator branchOp, const TSourceLoc& line)
700 {
701     return addBranch(branchOp, 0, line);
702 }
703
704 TIntermBranch* TIntermediate::addBranch(TOperator branchOp, TIntermTyped* expression, const TSourceLoc& line)
705 {
706     TIntermBranch* node = new TIntermBranch(branchOp, expression);
707     node->setLine(line);
708
709     return node;
710 }
711
712 //
713 // This is to be executed once the final root is put on top by the parsing
714 // process.
715 //
716 bool TIntermediate::postProcess(TIntermNode* root)
717 {
718     if (root == 0)
719         return true;
720
721     //
722     // First, finish off the top level sequence, if any
723     //
724     TIntermAggregate* aggRoot = root->getAsAggregate();
725     if (aggRoot && aggRoot->getOp() == EOpNull)
726         aggRoot->setOp(EOpSequence);
727
728     return true;
729 }
730
731 //
732 // This deletes the tree.
733 //
734 void TIntermediate::remove(TIntermNode* root)
735 {
736     if (root)
737         RemoveAllTreeNodes(root);
738 }
739
740 ////////////////////////////////////////////////////////////////
741 //
742 // Member functions of the nodes used for building the tree.
743 //
744 ////////////////////////////////////////////////////////////////
745
746 #define REPLACE_IF_IS(node, type, original, replacement) \
747     if (node == original) { \
748         node = static_cast<type *>(replacement); \
749         return true; \
750     }
751
752 bool TIntermLoop::replaceChildNode(
753     TIntermNode *original, TIntermNode *replacement)
754 {
755     REPLACE_IF_IS(init, TIntermNode, original, replacement);
756     REPLACE_IF_IS(cond, TIntermTyped, original, replacement);
757     REPLACE_IF_IS(expr, TIntermTyped, original, replacement);
758     REPLACE_IF_IS(body, TIntermNode, original, replacement);
759     return false;
760 }
761
762 void TIntermLoop::enqueueChildren(std::queue<TIntermNode*> *nodeQueue) const
763 {
764     if (init)
765     {
766         nodeQueue->push(init);
767     }
768     if (cond)
769     {
770         nodeQueue->push(cond);
771     }
772     if (expr)
773     {
774         nodeQueue->push(expr);
775     }
776     if (body)
777     {
778         nodeQueue->push(body);
779     }
780 }
781
782 bool TIntermBranch::replaceChildNode(
783     TIntermNode *original, TIntermNode *replacement)
784 {
785     REPLACE_IF_IS(expression, TIntermTyped, original, replacement);
786     return false;
787 }
788
789 void TIntermBranch::enqueueChildren(std::queue<TIntermNode*> *nodeQueue) const
790 {
791     if (expression)
792     {
793         nodeQueue->push(expression);
794     }
795 }
796
797 bool TIntermBinary::replaceChildNode(
798     TIntermNode *original, TIntermNode *replacement)
799 {
800     REPLACE_IF_IS(left, TIntermTyped, original, replacement);
801     REPLACE_IF_IS(right, TIntermTyped, original, replacement);
802     return false;
803 }
804
805 void TIntermBinary::enqueueChildren(std::queue<TIntermNode*> *nodeQueue) const
806 {
807     if (left)
808     {
809         nodeQueue->push(left);
810     }
811     if (right)
812     {
813         nodeQueue->push(right);
814     }
815 }
816
817 bool TIntermUnary::replaceChildNode(
818     TIntermNode *original, TIntermNode *replacement)
819 {
820     REPLACE_IF_IS(operand, TIntermTyped, original, replacement);
821     return false;
822 }
823
824 void TIntermUnary::enqueueChildren(std::queue<TIntermNode*> *nodeQueue) const
825 {
826     if (operand)
827     {
828         nodeQueue->push(operand);
829     }
830 }
831
832 bool TIntermAggregate::replaceChildNode(
833     TIntermNode *original, TIntermNode *replacement)
834 {
835     for (size_t ii = 0; ii < sequence.size(); ++ii)
836     {
837         REPLACE_IF_IS(sequence[ii], TIntermNode, original, replacement);
838     }
839     return false;
840 }
841
842 void TIntermAggregate::enqueueChildren(std::queue<TIntermNode*> *nodeQueue) const
843 {
844     for (size_t childIndex = 0; childIndex < sequence.size(); childIndex++)
845     {
846         nodeQueue->push(sequence[childIndex]);
847     }
848 }
849
850 bool TIntermSelection::replaceChildNode(
851     TIntermNode *original, TIntermNode *replacement)
852 {
853     REPLACE_IF_IS(condition, TIntermTyped, original, replacement);
854     REPLACE_IF_IS(trueBlock, TIntermNode, original, replacement);
855     REPLACE_IF_IS(falseBlock, TIntermNode, original, replacement);
856     return false;
857 }
858
859 void TIntermSelection::enqueueChildren(std::queue<TIntermNode*> *nodeQueue) const
860 {
861     if (condition)
862     {
863         nodeQueue->push(condition);
864     }
865     if (trueBlock)
866     {
867         nodeQueue->push(trueBlock);
868     }
869     if (falseBlock)
870     {
871         nodeQueue->push(falseBlock);
872     }
873 }
874
875 //
876 // Say whether or not an operation node changes the value of a variable.
877 //
878 bool TIntermOperator::isAssignment() const
879 {
880     switch (op) {
881         case EOpPostIncrement:
882         case EOpPostDecrement:
883         case EOpPreIncrement:
884         case EOpPreDecrement:
885         case EOpAssign:
886         case EOpAddAssign:
887         case EOpSubAssign:
888         case EOpMulAssign:
889         case EOpVectorTimesMatrixAssign:
890         case EOpVectorTimesScalarAssign:
891         case EOpMatrixTimesScalarAssign:
892         case EOpMatrixTimesMatrixAssign:
893         case EOpDivAssign:
894             return true;
895         default:
896             return false;
897     }
898 }
899
900 //
901 // returns true if the operator is for one of the constructors
902 //
903 bool TIntermOperator::isConstructor() const
904 {
905     switch (op) {
906         case EOpConstructVec2:
907         case EOpConstructVec3:
908         case EOpConstructVec4:
909         case EOpConstructMat2:
910         case EOpConstructMat3:
911         case EOpConstructMat4:
912         case EOpConstructFloat:
913         case EOpConstructIVec2:
914         case EOpConstructIVec3:
915         case EOpConstructIVec4:
916         case EOpConstructInt:
917         case EOpConstructBVec2:
918         case EOpConstructBVec3:
919         case EOpConstructBVec4:
920         case EOpConstructBool:
921         case EOpConstructStruct:
922             return true;
923         default:
924             return false;
925     }
926 }
927
928 //
929 // Make sure the type of a unary operator is appropriate for its
930 // combination of operation and operand type.
931 //
932 // Returns false in nothing makes sense.
933 //
934 bool TIntermUnary::promote(TInfoSink&)
935 {
936     switch (op) {
937         case EOpLogicalNot:
938             if (operand->getBasicType() != EbtBool)
939                 return false;
940             break;
941         case EOpNegative:
942         case EOpPostIncrement:
943         case EOpPostDecrement:
944         case EOpPreIncrement:
945         case EOpPreDecrement:
946             if (operand->getBasicType() == EbtBool)
947                 return false;
948             break;
949
950             // operators for built-ins are already type checked against their prototype
951         case EOpAny:
952         case EOpAll:
953         case EOpVectorLogicalNot:
954             return true;
955
956         default:
957             if (operand->getBasicType() != EbtFloat)
958                 return false;
959     }
960
961     setType(operand->getType());
962     type.setQualifier(EvqTemporary);
963
964     return true;
965 }
966
967 //
968 // Establishes the type of the resultant operation, as well as
969 // makes the operator the correct one for the operands.
970 //
971 // Returns false if operator can't work on operands.
972 //
973 bool TIntermBinary::promote(TInfoSink& infoSink)
974 {
975     // This function only handles scalars, vectors, and matrices.
976     if (left->isArray() || right->isArray()) {
977         infoSink.info.message(EPrefixInternalError, getLine(), "Invalid operation for arrays");
978         return false;
979     }
980
981     // GLSL ES 2.0 does not support implicit type casting.
982     // So the basic type should always match.
983     if (left->getBasicType() != right->getBasicType())
984         return false;
985
986     //
987     // Base assumption:  just make the type the same as the left
988     // operand.  Then only deviations from this need be coded.
989     //
990     setType(left->getType());
991
992     // The result gets promoted to the highest precision.
993     TPrecision higherPrecision = GetHigherPrecision(left->getPrecision(), right->getPrecision());
994     getTypePointer()->setPrecision(higherPrecision);
995
996     // Binary operations results in temporary variables unless both
997     // operands are const.
998     if (left->getQualifier() != EvqConst || right->getQualifier() != EvqConst) {
999         getTypePointer()->setQualifier(EvqTemporary);
1000     }
1001
1002     int size = std::max(left->getNominalSize(), right->getNominalSize());
1003
1004     //
1005     // All scalars. Code after this test assumes this case is removed!
1006     //
1007     if (size == 1) {
1008         switch (op) {
1009             //
1010             // Promote to conditional
1011             //
1012             case EOpEqual:
1013             case EOpNotEqual:
1014             case EOpLessThan:
1015             case EOpGreaterThan:
1016             case EOpLessThanEqual:
1017             case EOpGreaterThanEqual:
1018                 setType(TType(EbtBool, EbpUndefined));
1019                 break;
1020
1021             //
1022             // And and Or operate on conditionals
1023             //
1024             case EOpLogicalAnd:
1025             case EOpLogicalOr:
1026                 // Both operands must be of type bool.
1027                 if (left->getBasicType() != EbtBool || right->getBasicType() != EbtBool)
1028                     return false;
1029                 setType(TType(EbtBool, EbpUndefined));
1030                 break;
1031
1032             default:
1033                 break;
1034         }
1035         return true;
1036     }
1037
1038     // If we reach here, at least one of the operands is vector or matrix.
1039     // The other operand could be a scalar, vector, or matrix.
1040     // Are the sizes compatible?
1041     //
1042     if (left->getNominalSize() != right->getNominalSize()) {
1043         // If the nominal size of operands do not match:
1044         // One of them must be scalar.
1045         if (left->getNominalSize() != 1 && right->getNominalSize() != 1)
1046             return false;
1047         // Operator cannot be of type pure assignment.
1048         if (op == EOpAssign || op == EOpInitialize)
1049             return false;
1050     }
1051
1052     //
1053     // Can these two operands be combined?
1054     //
1055     TBasicType basicType = left->getBasicType();
1056     switch (op) {
1057         case EOpMul:
1058             if (!left->isMatrix() && right->isMatrix()) {
1059                 if (left->isVector())
1060                     op = EOpVectorTimesMatrix;
1061                 else {
1062                     op = EOpMatrixTimesScalar;
1063                     setType(TType(basicType, higherPrecision, EvqTemporary, size, true));
1064                 }
1065             } else if (left->isMatrix() && !right->isMatrix()) {
1066                 if (right->isVector()) {
1067                     op = EOpMatrixTimesVector;
1068                     setType(TType(basicType, higherPrecision, EvqTemporary, size, false));
1069                 } else {
1070                     op = EOpMatrixTimesScalar;
1071                 }
1072             } else if (left->isMatrix() && right->isMatrix()) {
1073                 op = EOpMatrixTimesMatrix;
1074             } else if (!left->isMatrix() && !right->isMatrix()) {
1075                 if (left->isVector() && right->isVector()) {
1076                     // leave as component product
1077                 } else if (left->isVector() || right->isVector()) {
1078                     op = EOpVectorTimesScalar;
1079                     setType(TType(basicType, higherPrecision, EvqTemporary, size, false));
1080                 }
1081             } else {
1082                 infoSink.info.message(EPrefixInternalError, getLine(), "Missing elses");
1083                 return false;
1084             }
1085             break;
1086         case EOpMulAssign:
1087             if (!left->isMatrix() && right->isMatrix()) {
1088                 if (left->isVector())
1089                     op = EOpVectorTimesMatrixAssign;
1090                 else {
1091                     return false;
1092                 }
1093             } else if (left->isMatrix() && !right->isMatrix()) {
1094                 if (right->isVector()) {
1095                     return false;
1096                 } else {
1097                     op = EOpMatrixTimesScalarAssign;
1098                 }
1099             } else if (left->isMatrix() && right->isMatrix()) {
1100                 op = EOpMatrixTimesMatrixAssign;
1101             } else if (!left->isMatrix() && !right->isMatrix()) {
1102                 if (left->isVector() && right->isVector()) {
1103                     // leave as component product
1104                 } else if (left->isVector() || right->isVector()) {
1105                     if (! left->isVector())
1106                         return false;
1107                     op = EOpVectorTimesScalarAssign;
1108                     setType(TType(basicType, higherPrecision, EvqTemporary, size, false));
1109                 }
1110             } else {
1111                 infoSink.info.message(EPrefixInternalError, getLine(), "Missing elses");
1112                 return false;
1113             }
1114             break;
1115
1116         case EOpAssign:
1117         case EOpInitialize:
1118         case EOpAdd:
1119         case EOpSub:
1120         case EOpDiv:
1121         case EOpAddAssign:
1122         case EOpSubAssign:
1123         case EOpDivAssign:
1124             if ((left->isMatrix() && right->isVector()) ||
1125                 (left->isVector() && right->isMatrix()))
1126                 return false;
1127             setType(TType(basicType, higherPrecision, EvqTemporary, size, left->isMatrix() || right->isMatrix()));
1128             break;
1129
1130         case EOpEqual:
1131         case EOpNotEqual:
1132         case EOpLessThan:
1133         case EOpGreaterThan:
1134         case EOpLessThanEqual:
1135         case EOpGreaterThanEqual:
1136             if ((left->isMatrix() && right->isVector()) ||
1137                 (left->isVector() && right->isMatrix()))
1138                 return false;
1139             setType(TType(EbtBool, EbpUndefined));
1140             break;
1141
1142         default:
1143             return false;
1144     }
1145     
1146     return true;
1147 }
1148
1149 bool CompareStruct(const TType& leftNodeType, ConstantUnion* rightUnionArray, ConstantUnion* leftUnionArray)
1150 {
1151     const TFieldList& fields = leftNodeType.getStruct()->fields();
1152
1153     size_t structSize = fields.size();
1154     size_t index = 0;
1155
1156     for (size_t j = 0; j < structSize; j++) {
1157         size_t size = fields[j]->type()->getObjectSize();
1158         for (size_t i = 0; i < size; i++) {
1159             if (fields[j]->type()->getBasicType() == EbtStruct) {
1160                 if (!CompareStructure(*(fields[j]->type()), &rightUnionArray[index], &leftUnionArray[index]))
1161                     return false;
1162             } else {
1163                 if (leftUnionArray[index] != rightUnionArray[index])
1164                     return false;
1165                 index++;
1166             }
1167         }
1168     }
1169     return true;
1170 }
1171
1172 bool CompareStructure(const TType& leftNodeType, ConstantUnion* rightUnionArray, ConstantUnion* leftUnionArray)
1173 {
1174     if (leftNodeType.isArray()) {
1175         TType typeWithoutArrayness = leftNodeType;
1176         typeWithoutArrayness.clearArrayness();
1177
1178         size_t arraySize = leftNodeType.getArraySize();
1179
1180         for (size_t i = 0; i < arraySize; ++i) {
1181             size_t offset = typeWithoutArrayness.getObjectSize() * i;
1182             if (!CompareStruct(typeWithoutArrayness, &rightUnionArray[offset], &leftUnionArray[offset]))
1183                 return false;
1184         }
1185     } else
1186         return CompareStruct(leftNodeType, rightUnionArray, leftUnionArray);
1187
1188     return true;
1189 }
1190
1191 //
1192 // The fold functions see if an operation on a constant can be done in place,
1193 // without generating run-time code.
1194 //
1195 // Returns the node to keep using, which may or may not be the node passed in.
1196 //
1197
1198 TIntermTyped* TIntermConstantUnion::fold(TOperator op, TIntermTyped* constantNode, TInfoSink& infoSink)
1199 {
1200     ConstantUnion *unionArray = getUnionArrayPointer();
1201
1202     if (!unionArray)
1203         return 0;
1204
1205     size_t objectSize = getType().getObjectSize();
1206
1207     if (constantNode) {  // binary operations
1208         TIntermConstantUnion *node = constantNode->getAsConstantUnion();
1209         ConstantUnion *rightUnionArray = node->getUnionArrayPointer();
1210         TType returnType = getType();
1211
1212         if (!rightUnionArray)
1213             return 0;
1214
1215         // for a case like float f = 1.2 + vec4(2,3,4,5);
1216         if (constantNode->getType().getObjectSize() == 1 && objectSize > 1) {
1217             rightUnionArray = new ConstantUnion[objectSize];
1218             for (size_t i = 0; i < objectSize; ++i)
1219                 rightUnionArray[i] = *node->getUnionArrayPointer();
1220             returnType = getType();
1221         } else if (constantNode->getType().getObjectSize() > 1 && objectSize == 1) {
1222             // for a case like float f = vec4(2,3,4,5) + 1.2;
1223             unionArray = new ConstantUnion[constantNode->getType().getObjectSize()];
1224             for (size_t i = 0; i < constantNode->getType().getObjectSize(); ++i)
1225                 unionArray[i] = *getUnionArrayPointer();
1226             returnType = node->getType();
1227             objectSize = constantNode->getType().getObjectSize();
1228         }
1229
1230         ConstantUnion* tempConstArray = 0;
1231         TIntermConstantUnion *tempNode;
1232
1233         bool boolNodeFlag = false;
1234         switch(op) {
1235             case EOpAdd:
1236                 tempConstArray = new ConstantUnion[objectSize];
1237                 {// support MSVC++6.0
1238                     for (size_t i = 0; i < objectSize; i++)
1239                         tempConstArray[i] = unionArray[i] + rightUnionArray[i];
1240                 }
1241                 break;
1242             case EOpSub:
1243                 tempConstArray = new ConstantUnion[objectSize];
1244                 {// support MSVC++6.0
1245                     for (size_t i = 0; i < objectSize; i++)
1246                         tempConstArray[i] = unionArray[i] - rightUnionArray[i];
1247                 }
1248                 break;
1249
1250             case EOpMul:
1251             case EOpVectorTimesScalar:
1252             case EOpMatrixTimesScalar:
1253                 tempConstArray = new ConstantUnion[objectSize];
1254                 {// support MSVC++6.0
1255                     for (size_t i = 0; i < objectSize; i++)
1256                         tempConstArray[i] = unionArray[i] * rightUnionArray[i];
1257                 }
1258                 break;
1259             case EOpMatrixTimesMatrix:
1260                 if (getType().getBasicType() != EbtFloat || node->getBasicType() != EbtFloat) {
1261                     infoSink.info.message(EPrefixInternalError, getLine(), "Constant Folding cannot be done for matrix multiply");
1262                     return 0;
1263                 }
1264                 {// support MSVC++6.0
1265                     int size = getNominalSize();
1266                     tempConstArray = new ConstantUnion[size*size];
1267                     for (int row = 0; row < size; row++) {
1268                         for (int column = 0; column < size; column++) {
1269                             tempConstArray[size * column + row].setFConst(0.0f);
1270                             for (int i = 0; i < size; i++) {
1271                                 tempConstArray[size * column + row].setFConst(tempConstArray[size * column + row].getFConst() + unionArray[i * size + row].getFConst() * (rightUnionArray[column * size + i].getFConst()));
1272                             }
1273                         }
1274                     }
1275                 }
1276                 break;
1277             case EOpDiv:
1278                 tempConstArray = new ConstantUnion[objectSize];
1279                 {// support MSVC++6.0
1280                     for (size_t i = 0; i < objectSize; i++) {
1281                         switch (getType().getBasicType()) {
1282             case EbtFloat:
1283                 if (rightUnionArray[i] == 0.0f) {
1284                     infoSink.info.message(EPrefixWarning, getLine(), "Divide by zero error during constant folding");
1285                     tempConstArray[i].setFConst(unionArray[i].getFConst() < 0 ? -FLT_MAX : FLT_MAX);
1286                 } else
1287                     tempConstArray[i].setFConst(unionArray[i].getFConst() / rightUnionArray[i].getFConst());
1288                 break;
1289
1290             case EbtInt:
1291                 if (rightUnionArray[i] == 0) {
1292                     infoSink.info.message(EPrefixWarning, getLine(), "Divide by zero error during constant folding");
1293                     tempConstArray[i].setIConst(INT_MAX);
1294                 } else
1295                     tempConstArray[i].setIConst(unionArray[i].getIConst() / rightUnionArray[i].getIConst());
1296                 break;
1297             default:
1298                 infoSink.info.message(EPrefixInternalError, getLine(), "Constant folding cannot be done for \"/\"");
1299                 return 0;
1300                         }
1301                     }
1302                 }
1303                 break;
1304
1305             case EOpMatrixTimesVector:
1306                 if (node->getBasicType() != EbtFloat) {
1307                     infoSink.info.message(EPrefixInternalError, getLine(), "Constant Folding cannot be done for matrix times vector");
1308                     return 0;
1309                 }
1310                 tempConstArray = new ConstantUnion[getNominalSize()];
1311
1312                 {// support MSVC++6.0
1313                     for (int size = getNominalSize(), i = 0; i < size; i++) {
1314                         tempConstArray[i].setFConst(0.0f);
1315                         for (int j = 0; j < size; j++) {
1316                             tempConstArray[i].setFConst(tempConstArray[i].getFConst() + ((unionArray[j*size + i].getFConst()) * rightUnionArray[j].getFConst()));
1317                         }
1318                     }
1319                 }
1320
1321                 tempNode = new TIntermConstantUnion(tempConstArray, node->getType());
1322                 tempNode->setLine(getLine());
1323
1324                 return tempNode;
1325
1326             case EOpVectorTimesMatrix:
1327                 if (getType().getBasicType() != EbtFloat) {
1328                     infoSink.info.message(EPrefixInternalError, getLine(), "Constant Folding cannot be done for vector times matrix");
1329                     return 0;
1330                 }
1331
1332                 tempConstArray = new ConstantUnion[getNominalSize()];
1333                 {// support MSVC++6.0
1334                     for (int size = getNominalSize(), i = 0; i < size; i++) {
1335                         tempConstArray[i].setFConst(0.0f);
1336                         for (int j = 0; j < size; j++) {
1337                             tempConstArray[i].setFConst(tempConstArray[i].getFConst() + ((unionArray[j].getFConst()) * rightUnionArray[i*size + j].getFConst()));
1338                         }
1339                     }
1340                 }
1341                 break;
1342
1343             case EOpLogicalAnd: // this code is written for possible future use, will not get executed currently
1344                 tempConstArray = new ConstantUnion[objectSize];
1345                 {// support MSVC++6.0
1346                     for (size_t i = 0; i < objectSize; i++)
1347                         tempConstArray[i] = unionArray[i] && rightUnionArray[i];
1348                 }
1349                 break;
1350
1351             case EOpLogicalOr: // this code is written for possible future use, will not get executed currently
1352                 tempConstArray = new ConstantUnion[objectSize];
1353                 {// support MSVC++6.0
1354                     for (size_t i = 0; i < objectSize; i++)
1355                         tempConstArray[i] = unionArray[i] || rightUnionArray[i];
1356                 }
1357                 break;
1358
1359             case EOpLogicalXor:
1360                 tempConstArray = new ConstantUnion[objectSize];
1361                 {// support MSVC++6.0
1362                     for (size_t i = 0; i < objectSize; i++)
1363                         switch (getType().getBasicType()) {
1364             case EbtBool: tempConstArray[i].setBConst((unionArray[i] == rightUnionArray[i]) ? false : true); break;
1365             default: assert(false && "Default missing");
1366                     }
1367                 }
1368                 break;
1369
1370             case EOpLessThan:
1371                 assert(objectSize == 1);
1372                 tempConstArray = new ConstantUnion[1];
1373                 tempConstArray->setBConst(*unionArray < *rightUnionArray);
1374                 returnType = TType(EbtBool, EbpUndefined, EvqConst);
1375                 break;
1376             case EOpGreaterThan:
1377                 assert(objectSize == 1);
1378                 tempConstArray = new ConstantUnion[1];
1379                 tempConstArray->setBConst(*unionArray > *rightUnionArray);
1380                 returnType = TType(EbtBool, EbpUndefined, EvqConst);
1381                 break;
1382             case EOpLessThanEqual:
1383                 {
1384                     assert(objectSize == 1);
1385                     ConstantUnion constant;
1386                     constant.setBConst(*unionArray > *rightUnionArray);
1387                     tempConstArray = new ConstantUnion[1];
1388                     tempConstArray->setBConst(!constant.getBConst());
1389                     returnType = TType(EbtBool, EbpUndefined, EvqConst);
1390                     break;
1391                 }
1392             case EOpGreaterThanEqual:
1393                 {
1394                     assert(objectSize == 1);
1395                     ConstantUnion constant;
1396                     constant.setBConst(*unionArray < *rightUnionArray);
1397                     tempConstArray = new ConstantUnion[1];
1398                     tempConstArray->setBConst(!constant.getBConst());
1399                     returnType = TType(EbtBool, EbpUndefined, EvqConst);
1400                     break;
1401                 }
1402
1403             case EOpEqual:
1404                 if (getType().getBasicType() == EbtStruct) {
1405                     if (!CompareStructure(node->getType(), node->getUnionArrayPointer(), unionArray))
1406                         boolNodeFlag = true;
1407                 } else {
1408                     for (size_t i = 0; i < objectSize; i++) {
1409                         if (unionArray[i] != rightUnionArray[i]) {
1410                             boolNodeFlag = true;
1411                             break;  // break out of for loop
1412                         }
1413                     }
1414                 }
1415
1416                 tempConstArray = new ConstantUnion[1];
1417                 if (!boolNodeFlag) {
1418                     tempConstArray->setBConst(true);
1419                 }
1420                 else {
1421                     tempConstArray->setBConst(false);
1422                 }
1423
1424                 tempNode = new TIntermConstantUnion(tempConstArray, TType(EbtBool, EbpUndefined, EvqConst));
1425                 tempNode->setLine(getLine());
1426
1427                 return tempNode;
1428
1429             case EOpNotEqual:
1430                 if (getType().getBasicType() == EbtStruct) {
1431                     if (CompareStructure(node->getType(), node->getUnionArrayPointer(), unionArray))
1432                         boolNodeFlag = true;
1433                 } else {
1434                     for (size_t i = 0; i < objectSize; i++) {
1435                         if (unionArray[i] == rightUnionArray[i]) {
1436                             boolNodeFlag = true;
1437                             break;  // break out of for loop
1438                         }
1439                     }
1440                 }
1441
1442                 tempConstArray = new ConstantUnion[1];
1443                 if (!boolNodeFlag) {
1444                     tempConstArray->setBConst(true);
1445                 }
1446                 else {
1447                     tempConstArray->setBConst(false);
1448                 }
1449
1450                 tempNode = new TIntermConstantUnion(tempConstArray, TType(EbtBool, EbpUndefined, EvqConst));
1451                 tempNode->setLine(getLine());
1452
1453                 return tempNode;
1454
1455             default:
1456                 infoSink.info.message(EPrefixInternalError, getLine(), "Invalid operator for constant folding");
1457                 return 0;
1458         }
1459         tempNode = new TIntermConstantUnion(tempConstArray, returnType);
1460         tempNode->setLine(getLine());
1461
1462         return tempNode;
1463     } else {
1464         //
1465         // Do unary operations
1466         //
1467         TIntermConstantUnion *newNode = 0;
1468         ConstantUnion* tempConstArray = new ConstantUnion[objectSize];
1469         for (size_t i = 0; i < objectSize; i++) {
1470             switch(op) {
1471                 case EOpNegative:
1472                     switch (getType().getBasicType()) {
1473                         case EbtFloat: tempConstArray[i].setFConst(-unionArray[i].getFConst()); break;
1474                         case EbtInt:   tempConstArray[i].setIConst(-unionArray[i].getIConst()); break;
1475                         default:
1476                             infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1477                             return 0;
1478                     }
1479                     break;
1480                 case EOpLogicalNot: // this code is written for possible future use, will not get executed currently
1481                     switch (getType().getBasicType()) {
1482                         case EbtBool:  tempConstArray[i].setBConst(!unionArray[i].getBConst()); break;
1483                         default:
1484                             infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1485                             return 0;
1486                     }
1487                     break;
1488                 default:
1489                     return 0;
1490             }
1491         }
1492         newNode = new TIntermConstantUnion(tempConstArray, getType());
1493         newNode->setLine(getLine());
1494         return newNode;
1495     }
1496 }
1497
1498 TIntermTyped* TIntermediate::promoteConstantUnion(TBasicType promoteTo, TIntermConstantUnion* node)
1499 {
1500     size_t size = node->getType().getObjectSize();
1501
1502     ConstantUnion *leftUnionArray = new ConstantUnion[size];
1503
1504     for (size_t i = 0; i < size; i++) {
1505
1506         switch (promoteTo) {
1507             case EbtFloat:
1508                 switch (node->getType().getBasicType()) {
1509                     case EbtInt:
1510                         leftUnionArray[i].setFConst(static_cast<float>(node->getIConst(i)));
1511                         break;
1512                     case EbtBool:
1513                         leftUnionArray[i].setFConst(static_cast<float>(node->getBConst(i)));
1514                         break;
1515                     case EbtFloat:
1516                         leftUnionArray[i].setFConst(static_cast<float>(node->getFConst(i)));
1517                         break;
1518                     default:
1519                         infoSink.info.message(EPrefixInternalError, node->getLine(), "Cannot promote");
1520                         return 0;
1521                 }
1522                 break;
1523             case EbtInt:
1524                 switch (node->getType().getBasicType()) {
1525                     case EbtInt:
1526                         leftUnionArray[i].setIConst(static_cast<int>(node->getIConst(i)));
1527                         break;
1528                     case EbtBool:
1529                         leftUnionArray[i].setIConst(static_cast<int>(node->getBConst(i)));
1530                         break;
1531                     case EbtFloat:
1532                         leftUnionArray[i].setIConst(static_cast<int>(node->getFConst(i)));
1533                         break;
1534                     default:
1535                         infoSink.info.message(EPrefixInternalError, node->getLine(), "Cannot promote");
1536                         return 0;
1537                 }
1538                 break;
1539             case EbtBool:
1540                 switch (node->getType().getBasicType()) {
1541                     case EbtInt:
1542                         leftUnionArray[i].setBConst(node->getIConst(i) != 0);
1543                         break;
1544                     case EbtBool:
1545                         leftUnionArray[i].setBConst(node->getBConst(i));
1546                         break;
1547                     case EbtFloat:
1548                         leftUnionArray[i].setBConst(node->getFConst(i) != 0.0f);
1549                         break;
1550                     default:
1551                         infoSink.info.message(EPrefixInternalError, node->getLine(), "Cannot promote");
1552                         return 0;
1553                 }
1554
1555                 break;
1556             default:
1557                 infoSink.info.message(EPrefixInternalError, node->getLine(), "Incorrect data type found");
1558                 return 0;
1559         }
1560
1561     }
1562
1563     const TType& t = node->getType();
1564
1565     return addConstantUnion(leftUnionArray, TType(promoteTo, t.getPrecision(), t.getQualifier(), t.getNominalSize(), t.isMatrix(), t.isArray()), node->getLine());
1566 }
1567
1568 // static
1569 TString TIntermTraverser::hash(const TString& name, ShHashFunction64 hashFunction)
1570 {
1571     if (hashFunction == NULL || name.empty())
1572         return name;
1573     khronos_uint64_t number = (*hashFunction)(name.c_str(), name.length());
1574     TStringStream stream;
1575     stream << HASHED_NAME_PREFIX << std::hex << number;
1576     TString hashedName = stream.str();
1577     return hashedName;
1578 }