OSDN Git Service

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