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