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