2 // Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
8 // Build the intermediate representation.
15 #include "compiler/translator/HashNames.h"
16 #include "compiler/translator/localintermediate.h"
17 #include "compiler/translator/QualifierAlive.h"
18 #include "compiler/translator/RemoveTree.h"
20 bool CompareStructure(const TType& leftNodeType, ConstantUnion* rightUnionArray, ConstantUnion* leftUnionArray);
22 static TPrecision GetHigherPrecision(TPrecision left, TPrecision right)
24 return left > right ? left : right;
27 const char* getOperatorString(TOperator op)
30 case EOpInitialize: return "=";
31 case EOpAssign: return "=";
32 case EOpAddAssign: return "+=";
33 case EOpSubAssign: return "-=";
34 case EOpDivAssign: return "/=";
38 case EOpVectorTimesMatrixAssign:
39 case EOpVectorTimesScalarAssign:
40 case EOpMatrixTimesScalarAssign:
41 case EOpMatrixTimesMatrixAssign: return "*=";
45 case EOpIndexIndirect: return "[]";
47 case EOpIndexDirectStruct: return ".";
48 case EOpVectorSwizzle: return ".";
49 case EOpAdd: return "+";
50 case EOpSub: return "-";
51 case EOpMul: return "*";
52 case EOpDiv: return "/";
53 case EOpMod: UNIMPLEMENTED(); break;
54 case EOpEqual: return "==";
55 case EOpNotEqual: return "!=";
56 case EOpLessThan: return "<";
57 case EOpGreaterThan: return ">";
58 case EOpLessThanEqual: return "<=";
59 case EOpGreaterThanEqual: return ">=";
62 case EOpVectorTimesScalar:
63 case EOpVectorTimesMatrix:
64 case EOpMatrixTimesVector:
65 case EOpMatrixTimesScalar:
66 case EOpMatrixTimesMatrix: return "*";
68 case EOpLogicalOr: return "||";
69 case EOpLogicalXor: return "^^";
70 case EOpLogicalAnd: return "&&";
71 case EOpNegative: return "-";
72 case EOpVectorLogicalNot: return "not";
73 case EOpLogicalNot: return "!";
74 case EOpPostIncrement: return "++";
75 case EOpPostDecrement: return "--";
76 case EOpPreIncrement: return "++";
77 case EOpPreDecrement: return "--";
80 case EOpConvIntToBool:
81 case EOpConvFloatToBool: return "bool";
84 case EOpConvBoolToFloat:
85 case EOpConvIntToFloat: return "float";
88 case EOpConvFloatToInt:
89 case EOpConvBoolToInt: return "int";
91 case EOpRadians: return "radians";
92 case EOpDegrees: return "degrees";
93 case EOpSin: return "sin";
94 case EOpCos: return "cos";
95 case EOpTan: return "tan";
96 case EOpAsin: return "asin";
97 case EOpAcos: return "acos";
98 case EOpAtan: return "atan";
99 case EOpExp: return "exp";
100 case EOpLog: return "log";
101 case EOpExp2: return "exp2";
102 case EOpLog2: return "log2";
103 case EOpSqrt: return "sqrt";
104 case EOpInverseSqrt: return "inversesqrt";
105 case EOpAbs: return "abs";
106 case EOpSign: return "sign";
107 case EOpFloor: return "floor";
108 case EOpCeil: return "ceil";
109 case EOpFract: return "fract";
110 case EOpLength: return "length";
111 case EOpNormalize: return "normalize";
112 case EOpDFdx: return "dFdx";
113 case EOpDFdy: return "dFdy";
114 case EOpFwidth: return "fwidth";
115 case EOpAny: return "any";
116 case EOpAll: return "all";
123 ////////////////////////////////////////////////////////////////////////////
125 // First set of functions are to help build the intermediate representation.
126 // These functions are not member functions of the nodes.
127 // They are called from parser productions.
129 /////////////////////////////////////////////////////////////////////////////
132 // Add a terminal node for an identifier in an expression.
134 // Returns the added node.
136 TIntermSymbol* TIntermediate::addSymbol(int id, const TString& name, const TType& type, const TSourceLoc& line)
138 TIntermSymbol* node = new TIntermSymbol(id, name, type);
145 // Connect two nodes with a new parent that does a binary operation on the nodes.
147 // Returns the added node.
149 TIntermTyped* TIntermediate::addBinaryMath(TOperator op, TIntermTyped* left, TIntermTyped* right, const TSourceLoc& line, TSymbolTable& symbolTable)
159 case EOpLessThanEqual:
160 case EOpGreaterThanEqual:
161 if (left->isMatrix() || left->isArray() || left->isVector() || left->getBasicType() == EbtStruct) {
168 if (left->getBasicType() != EbtBool || left->isMatrix() || left->isArray() || left->isVector()) {
176 if (left->getBasicType() == EbtStruct || left->getBasicType() == EbtBool)
182 // First try converting the children to compatible types.
184 if (left->getType().getStruct() && right->getType().getStruct()) {
185 if (left->getType() != right->getType())
188 TIntermTyped* child = addConversion(op, left->getType(), right);
192 child = addConversion(op, right->getType(), left);
201 // Need a new node holding things together then. Make
202 // one and promote it to the right type.
204 TIntermBinary* node = new TIntermBinary(op);
208 node->setRight(right);
209 if (!node->promote(infoSink))
213 // See if we can fold constants.
215 TIntermTyped* typedReturnNode = 0;
216 TIntermConstantUnion *leftTempConstant = left->getAsConstantUnion();
217 TIntermConstantUnion *rightTempConstant = right->getAsConstantUnion();
218 if (leftTempConstant && rightTempConstant) {
219 typedReturnNode = leftTempConstant->fold(node->getOp(), rightTempConstant, infoSink);
222 return typedReturnNode;
229 // Connect two nodes through an assignment.
231 // Returns the added node.
233 TIntermTyped* TIntermediate::addAssign(TOperator op, TIntermTyped* left, TIntermTyped* right, const TSourceLoc& line)
236 // Like adding binary math, except the conversion can only go
237 // from right to left.
239 TIntermBinary* node = new TIntermBinary(op);
242 TIntermTyped* child = addConversion(op, left->getType(), right);
247 node->setRight(child);
248 if (! node->promote(infoSink))
255 // Connect two nodes through an index operator, where the left node is the base
256 // of an array or struct, and the right node is a direct or indirect offset.
258 // Returns the added node.
259 // The caller should set the type of the returned node.
261 TIntermTyped* TIntermediate::addIndex(TOperator op, TIntermTyped* base, TIntermTyped* index, const TSourceLoc& line)
263 TIntermBinary* node = new TIntermBinary(op);
266 node->setRight(index);
268 // caller should set the type
274 // Add one node as the parent of another that it operates on.
276 // Returns the added node.
278 TIntermTyped* TIntermediate::addUnaryMath(TOperator op, TIntermNode* childNode, const TSourceLoc& line, TSymbolTable& symbolTable)
281 TIntermTyped* child = childNode->getAsTyped();
284 infoSink.info.message(EPrefixInternalError, line, "Bad type in AddUnaryMath");
290 if (child->getType().getBasicType() != EbtBool || child->getType().isMatrix() || child->getType().isArray() || child->getType().isVector()) {
295 case EOpPostIncrement:
296 case EOpPreIncrement:
297 case EOpPostDecrement:
298 case EOpPreDecrement:
300 if (child->getType().getBasicType() == EbtStruct || child->getType().isArray())
306 // Do we need to promote the operand?
308 // Note: Implicit promotions were removed from the language.
310 TBasicType newType = EbtVoid;
312 case EOpConstructInt: newType = EbtInt; break;
313 case EOpConstructBool: newType = EbtBool; break;
314 case EOpConstructFloat: newType = EbtFloat; break;
318 if (newType != EbtVoid) {
319 child = addConversion(op, TType(newType, child->getPrecision(), EvqTemporary,
320 child->getNominalSize(),
329 // For constructors, we are now done, it's all in the conversion.
332 case EOpConstructInt:
333 case EOpConstructBool:
334 case EOpConstructFloat:
339 TIntermConstantUnion *childTempConstant = 0;
340 if (child->getAsConstantUnion())
341 childTempConstant = child->getAsConstantUnion();
344 // Make a new node for the operator.
346 node = new TIntermUnary(op);
348 node->setOperand(child);
350 if (! node->promote(infoSink))
353 if (childTempConstant) {
354 TIntermTyped* newChild = childTempConstant->fold(op, 0, infoSink);
364 // This is the safe way to change the operator on an aggregate, as it
365 // does lots of error checking and fixing. Especially for establishing
366 // a function call's operation on it's set of parameters. Sequences
367 // of instructions are also aggregates, but they just direnctly set
368 // their operator to EOpSequence.
370 // Returns an aggregate node, which could be the one passed in if
371 // it was already an aggregate but no operator was set.
373 TIntermAggregate* TIntermediate::setAggregateOperator(TIntermNode* node, TOperator op, const TSourceLoc& line)
375 TIntermAggregate* aggNode;
378 // Make sure we have an aggregate. If not turn it into one.
381 aggNode = node->getAsAggregate();
382 if (aggNode == 0 || aggNode->getOp() != EOpNull) {
384 // Make an aggregate containing this node.
386 aggNode = new TIntermAggregate();
387 aggNode->getSequence().push_back(node);
390 aggNode = new TIntermAggregate();
396 aggNode->setLine(line);
402 // Convert one type to another.
404 // Returns the node representing the conversion, which could be the same
405 // node passed in if no conversion was needed.
407 // Return 0 if a conversion can't be done.
409 TIntermTyped* TIntermediate::addConversion(TOperator op, const TType& type, TIntermTyped* node)
412 // Does the base type allow operation?
414 switch (node->getBasicType()) {
423 // Otherwise, if types are identical, no problem
425 if (type == node->getType())
429 // If one's a structure, then no conversions.
431 if (type.getStruct() || node->getType().getStruct())
435 // If one's an array, then no conversions.
437 if (type.isArray() || node->getType().isArray())
440 TBasicType promoteTo;
444 // Explicit conversions
446 case EOpConstructBool:
449 case EOpConstructFloat:
450 promoteTo = EbtFloat;
452 case EOpConstructInt:
457 // implicit conversions were removed from the language.
459 if (type.getBasicType() != node->getType().getBasicType())
462 // Size and structure could still differ, but that's
463 // handled by operator promotion.
468 if (node->getAsConstantUnion()) {
470 return (promoteConstantUnion(promoteTo, node->getAsConstantUnion()));
474 // Add a new newNode for the conversion.
476 TIntermUnary* newNode = 0;
478 TOperator newOp = EOpNull;
481 switch (node->getBasicType()) {
482 case EbtInt: newOp = EOpConvIntToFloat; break;
483 case EbtBool: newOp = EOpConvBoolToFloat; break;
485 infoSink.info.message(EPrefixInternalError, node->getLine(), "Bad promotion node");
490 switch (node->getBasicType()) {
491 case EbtInt: newOp = EOpConvIntToBool; break;
492 case EbtFloat: newOp = EOpConvFloatToBool; break;
494 infoSink.info.message(EPrefixInternalError, node->getLine(), "Bad promotion node");
499 switch (node->getBasicType()) {
500 case EbtBool: newOp = EOpConvBoolToInt; break;
501 case EbtFloat: newOp = EOpConvFloatToInt; break;
503 infoSink.info.message(EPrefixInternalError, node->getLine(), "Bad promotion node");
508 infoSink.info.message(EPrefixInternalError, node->getLine(), "Bad promotion type");
512 TType type(promoteTo, node->getPrecision(), EvqTemporary, node->getNominalSize(), node->isMatrix(), node->isArray());
513 newNode = new TIntermUnary(newOp, type);
514 newNode->setLine(node->getLine());
515 newNode->setOperand(node);
522 // Safe way to combine two nodes into an aggregate. Works with null pointers,
523 // a node that's not a aggregate yet, etc.
525 // Returns the resulting aggregate, unless 0 was passed in for
526 // both existing nodes.
528 TIntermAggregate* TIntermediate::growAggregate(TIntermNode* left, TIntermNode* right, const TSourceLoc& line)
530 if (left == 0 && right == 0)
533 TIntermAggregate* aggNode = 0;
535 aggNode = left->getAsAggregate();
536 if (!aggNode || aggNode->getOp() != EOpNull) {
537 aggNode = new TIntermAggregate;
539 aggNode->getSequence().push_back(left);
543 aggNode->getSequence().push_back(right);
545 aggNode->setLine(line);
551 // Turn an existing node into an aggregate.
553 // Returns an aggregate, unless 0 was passed in for the existing node.
555 TIntermAggregate* TIntermediate::makeAggregate(TIntermNode* node, const TSourceLoc& line)
560 TIntermAggregate* aggNode = new TIntermAggregate;
561 aggNode->getSequence().push_back(node);
562 aggNode->setLine(line);
568 // For "if" test nodes. There are three children; a condition,
569 // a true path, and a false path. The two paths are in the
572 // Returns the selection node created.
574 TIntermNode* TIntermediate::addSelection(TIntermTyped* cond, TIntermNodePair nodePair, const TSourceLoc& line)
577 // For compile time constant selections, prune the code and
581 if (cond->getAsTyped() && cond->getAsTyped()->getAsConstantUnion()) {
582 if (cond->getAsConstantUnion()->getBConst(0) == true)
583 return nodePair.node1 ? setAggregateOperator(nodePair.node1, EOpSequence, nodePair.node1->getLine()) : NULL;
585 return nodePair.node2 ? setAggregateOperator(nodePair.node2, EOpSequence, nodePair.node2->getLine()) : NULL;
588 TIntermSelection* node = new TIntermSelection(cond, nodePair.node1, nodePair.node2);
595 TIntermTyped* TIntermediate::addComma(TIntermTyped* left, TIntermTyped* right, const TSourceLoc& line)
597 if (left->getType().getQualifier() == EvqConst && right->getType().getQualifier() == EvqConst) {
600 TIntermTyped *commaAggregate = growAggregate(left, right, line);
601 commaAggregate->getAsAggregate()->setOp(EOpComma);
602 commaAggregate->setType(right->getType());
603 commaAggregate->getTypePointer()->setQualifier(EvqTemporary);
604 return commaAggregate;
609 // For "?:" test nodes. There are three children; a condition,
610 // a true path, and a false path. The two paths are specified
611 // as separate parameters.
613 // Returns the selection node created, or 0 if one could not be.
615 TIntermTyped* TIntermediate::addSelection(TIntermTyped* cond, TIntermTyped* trueBlock, TIntermTyped* falseBlock, const TSourceLoc& line)
618 // Get compatible types.
620 TIntermTyped* child = addConversion(EOpSequence, trueBlock->getType(), falseBlock);
624 child = addConversion(EOpSequence, falseBlock->getType(), trueBlock);
632 // See if all the operands are constant, then fold it otherwise not.
635 if (cond->getAsConstantUnion() && trueBlock->getAsConstantUnion() && falseBlock->getAsConstantUnion()) {
636 if (cond->getAsConstantUnion()->getBConst(0))
643 // Make a selection node.
645 TIntermSelection* node = new TIntermSelection(cond, trueBlock, falseBlock, trueBlock->getType());
646 node->getTypePointer()->setQualifier(EvqTemporary);
653 // Constant terminal nodes. Has a union that contains bool, float or int constants
655 // Returns the constant union node created.
658 TIntermConstantUnion* TIntermediate::addConstantUnion(ConstantUnion* unionArrayPointer, const TType& t, const TSourceLoc& line)
660 TIntermConstantUnion* node = new TIntermConstantUnion(unionArrayPointer, t);
666 TIntermTyped* TIntermediate::addSwizzle(TVectorFields& fields, const TSourceLoc& line)
669 TIntermAggregate* node = new TIntermAggregate(EOpSequence);
672 TIntermConstantUnion* constIntNode;
673 TIntermSequence &sequenceVector = node->getSequence();
674 ConstantUnion* unionArray;
676 for (int i = 0; i < fields.num; i++) {
677 unionArray = new ConstantUnion[1];
678 unionArray->setIConst(fields.offsets[i]);
679 constIntNode = addConstantUnion(unionArray, TType(EbtInt, EbpUndefined, EvqConst), line);
680 sequenceVector.push_back(constIntNode);
687 // Create loop nodes.
689 TIntermNode* TIntermediate::addLoop(TLoopType type, TIntermNode* init, TIntermTyped* cond, TIntermTyped* expr, TIntermNode* body, const TSourceLoc& line)
691 TIntermNode* node = new TIntermLoop(type, init, cond, expr, body);
700 TIntermBranch* TIntermediate::addBranch(TOperator branchOp, const TSourceLoc& line)
702 return addBranch(branchOp, 0, line);
705 TIntermBranch* TIntermediate::addBranch(TOperator branchOp, TIntermTyped* expression, const TSourceLoc& line)
707 TIntermBranch* node = new TIntermBranch(branchOp, expression);
714 // This is to be executed once the final root is put on top by the parsing
717 bool TIntermediate::postProcess(TIntermNode* root)
723 // First, finish off the top level sequence, if any
725 TIntermAggregate* aggRoot = root->getAsAggregate();
726 if (aggRoot && aggRoot->getOp() == EOpNull)
727 aggRoot->setOp(EOpSequence);
733 // This deletes the tree.
735 void TIntermediate::remove(TIntermNode* root)
738 RemoveAllTreeNodes(root);
741 ////////////////////////////////////////////////////////////////
743 // Member functions of the nodes used for building the tree.
745 ////////////////////////////////////////////////////////////////
747 #define REPLACE_IF_IS(node, type, original, replacement) \
748 if (node == original) { \
749 node = static_cast<type *>(replacement); \
753 bool TIntermLoop::replaceChildNode(
754 TIntermNode *original, TIntermNode *replacement)
756 REPLACE_IF_IS(init, TIntermNode, original, replacement);
757 REPLACE_IF_IS(cond, TIntermTyped, original, replacement);
758 REPLACE_IF_IS(expr, TIntermTyped, original, replacement);
759 REPLACE_IF_IS(body, TIntermNode, original, replacement);
763 bool TIntermBranch::replaceChildNode(
764 TIntermNode *original, TIntermNode *replacement)
766 REPLACE_IF_IS(expression, TIntermTyped, original, replacement);
770 bool TIntermBinary::replaceChildNode(
771 TIntermNode *original, TIntermNode *replacement)
773 REPLACE_IF_IS(left, TIntermTyped, original, replacement);
774 REPLACE_IF_IS(right, TIntermTyped, original, replacement);
778 bool TIntermUnary::replaceChildNode(
779 TIntermNode *original, TIntermNode *replacement)
781 REPLACE_IF_IS(operand, TIntermTyped, original, replacement);
785 bool TIntermAggregate::replaceChildNode(
786 TIntermNode *original, TIntermNode *replacement)
788 for (size_t ii = 0; ii < sequence.size(); ++ii)
790 REPLACE_IF_IS(sequence[ii], TIntermNode, original, replacement);
795 bool TIntermSelection::replaceChildNode(
796 TIntermNode *original, TIntermNode *replacement)
798 REPLACE_IF_IS(condition, TIntermTyped, original, replacement);
799 REPLACE_IF_IS(trueBlock, TIntermNode, original, replacement);
800 REPLACE_IF_IS(falseBlock, TIntermNode, original, replacement);
805 // Say whether or not an operation node changes the value of a variable.
807 bool TIntermOperator::isAssignment() const
810 case EOpPostIncrement:
811 case EOpPostDecrement:
812 case EOpPreIncrement:
813 case EOpPreDecrement:
818 case EOpVectorTimesMatrixAssign:
819 case EOpVectorTimesScalarAssign:
820 case EOpMatrixTimesScalarAssign:
821 case EOpMatrixTimesMatrixAssign:
830 // returns true if the operator is for one of the constructors
832 bool TIntermOperator::isConstructor() const
835 case EOpConstructVec2:
836 case EOpConstructVec3:
837 case EOpConstructVec4:
838 case EOpConstructMat2:
839 case EOpConstructMat3:
840 case EOpConstructMat4:
841 case EOpConstructFloat:
842 case EOpConstructIVec2:
843 case EOpConstructIVec3:
844 case EOpConstructIVec4:
845 case EOpConstructInt:
846 case EOpConstructBVec2:
847 case EOpConstructBVec3:
848 case EOpConstructBVec4:
849 case EOpConstructBool:
850 case EOpConstructStruct:
858 // Make sure the type of a unary operator is appropriate for its
859 // combination of operation and operand type.
861 // Returns false in nothing makes sense.
863 bool TIntermUnary::promote(TInfoSink&)
867 if (operand->getBasicType() != EbtBool)
871 case EOpPostIncrement:
872 case EOpPostDecrement:
873 case EOpPreIncrement:
874 case EOpPreDecrement:
875 if (operand->getBasicType() == EbtBool)
879 // operators for built-ins are already type checked against their prototype
882 case EOpVectorLogicalNot:
886 if (operand->getBasicType() != EbtFloat)
890 setType(operand->getType());
891 type.setQualifier(EvqTemporary);
897 // Establishes the type of the resultant operation, as well as
898 // makes the operator the correct one for the operands.
900 // Returns false if operator can't work on operands.
902 bool TIntermBinary::promote(TInfoSink& infoSink)
904 // This function only handles scalars, vectors, and matrices.
905 if (left->isArray() || right->isArray()) {
906 infoSink.info.message(EPrefixInternalError, getLine(), "Invalid operation for arrays");
910 // GLSL ES 2.0 does not support implicit type casting.
911 // So the basic type should always match.
912 if (left->getBasicType() != right->getBasicType())
916 // Base assumption: just make the type the same as the left
917 // operand. Then only deviations from this need be coded.
919 setType(left->getType());
921 // The result gets promoted to the highest precision.
922 TPrecision higherPrecision = GetHigherPrecision(left->getPrecision(), right->getPrecision());
923 getTypePointer()->setPrecision(higherPrecision);
925 // Binary operations results in temporary variables unless both
926 // operands are const.
927 if (left->getQualifier() != EvqConst || right->getQualifier() != EvqConst) {
928 getTypePointer()->setQualifier(EvqTemporary);
931 int size = std::max(left->getNominalSize(), right->getNominalSize());
934 // All scalars. Code after this test assumes this case is removed!
939 // Promote to conditional
945 case EOpLessThanEqual:
946 case EOpGreaterThanEqual:
947 setType(TType(EbtBool, EbpUndefined));
951 // And and Or operate on conditionals
955 // Both operands must be of type bool.
956 if (left->getBasicType() != EbtBool || right->getBasicType() != EbtBool)
958 setType(TType(EbtBool, EbpUndefined));
967 // If we reach here, at least one of the operands is vector or matrix.
968 // The other operand could be a scalar, vector, or matrix.
969 // Are the sizes compatible?
971 if (left->getNominalSize() != right->getNominalSize()) {
972 // If the nominal size of operands do not match:
973 // One of them must be scalar.
974 if (left->getNominalSize() != 1 && right->getNominalSize() != 1)
976 // Operator cannot be of type pure assignment.
977 if (op == EOpAssign || op == EOpInitialize)
982 // Can these two operands be combined?
984 TBasicType basicType = left->getBasicType();
987 if (!left->isMatrix() && right->isMatrix()) {
988 if (left->isVector())
989 op = EOpVectorTimesMatrix;
991 op = EOpMatrixTimesScalar;
992 setType(TType(basicType, higherPrecision, EvqTemporary, size, true));
994 } else if (left->isMatrix() && !right->isMatrix()) {
995 if (right->isVector()) {
996 op = EOpMatrixTimesVector;
997 setType(TType(basicType, higherPrecision, EvqTemporary, size, false));
999 op = EOpMatrixTimesScalar;
1001 } else if (left->isMatrix() && right->isMatrix()) {
1002 op = EOpMatrixTimesMatrix;
1003 } else if (!left->isMatrix() && !right->isMatrix()) {
1004 if (left->isVector() && right->isVector()) {
1005 // leave as component product
1006 } else if (left->isVector() || right->isVector()) {
1007 op = EOpVectorTimesScalar;
1008 setType(TType(basicType, higherPrecision, EvqTemporary, size, false));
1011 infoSink.info.message(EPrefixInternalError, getLine(), "Missing elses");
1016 if (!left->isMatrix() && right->isMatrix()) {
1017 if (left->isVector())
1018 op = EOpVectorTimesMatrixAssign;
1022 } else if (left->isMatrix() && !right->isMatrix()) {
1023 if (right->isVector()) {
1026 op = EOpMatrixTimesScalarAssign;
1028 } else if (left->isMatrix() && right->isMatrix()) {
1029 op = EOpMatrixTimesMatrixAssign;
1030 } else if (!left->isMatrix() && !right->isMatrix()) {
1031 if (left->isVector() && right->isVector()) {
1032 // leave as component product
1033 } else if (left->isVector() || right->isVector()) {
1034 if (! left->isVector())
1036 op = EOpVectorTimesScalarAssign;
1037 setType(TType(basicType, higherPrecision, EvqTemporary, size, false));
1040 infoSink.info.message(EPrefixInternalError, getLine(), "Missing elses");
1053 if ((left->isMatrix() && right->isVector()) ||
1054 (left->isVector() && right->isMatrix()))
1056 setType(TType(basicType, higherPrecision, EvqTemporary, size, left->isMatrix() || right->isMatrix()));
1062 case EOpGreaterThan:
1063 case EOpLessThanEqual:
1064 case EOpGreaterThanEqual:
1065 if ((left->isMatrix() && right->isVector()) ||
1066 (left->isVector() && right->isMatrix()))
1068 setType(TType(EbtBool, EbpUndefined));
1078 bool CompareStruct(const TType& leftNodeType, ConstantUnion* rightUnionArray, ConstantUnion* leftUnionArray)
1080 const TFieldList& fields = leftNodeType.getStruct()->fields();
1082 size_t structSize = fields.size();
1085 for (size_t j = 0; j < structSize; j++) {
1086 size_t size = fields[j]->type()->getObjectSize();
1087 for (size_t i = 0; i < size; i++) {
1088 if (fields[j]->type()->getBasicType() == EbtStruct) {
1089 if (!CompareStructure(*(fields[j]->type()), &rightUnionArray[index], &leftUnionArray[index]))
1092 if (leftUnionArray[index] != rightUnionArray[index])
1101 bool CompareStructure(const TType& leftNodeType, ConstantUnion* rightUnionArray, ConstantUnion* leftUnionArray)
1103 if (leftNodeType.isArray()) {
1104 TType typeWithoutArrayness = leftNodeType;
1105 typeWithoutArrayness.clearArrayness();
1107 size_t arraySize = leftNodeType.getArraySize();
1109 for (size_t i = 0; i < arraySize; ++i) {
1110 size_t offset = typeWithoutArrayness.getObjectSize() * i;
1111 if (!CompareStruct(typeWithoutArrayness, &rightUnionArray[offset], &leftUnionArray[offset]))
1115 return CompareStruct(leftNodeType, rightUnionArray, leftUnionArray);
1121 // The fold functions see if an operation on a constant can be done in place,
1122 // without generating run-time code.
1124 // Returns the node to keep using, which may or may not be the node passed in.
1127 TIntermTyped* TIntermConstantUnion::fold(TOperator op, TIntermTyped* constantNode, TInfoSink& infoSink)
1129 ConstantUnion *unionArray = getUnionArrayPointer();
1130 size_t objectSize = getType().getObjectSize();
1132 if (constantNode) { // binary operations
1133 TIntermConstantUnion *node = constantNode->getAsConstantUnion();
1134 ConstantUnion *rightUnionArray = node->getUnionArrayPointer();
1135 TType returnType = getType();
1137 // for a case like float f = 1.2 + vec4(2,3,4,5);
1138 if (constantNode->getType().getObjectSize() == 1 && objectSize > 1) {
1139 rightUnionArray = new ConstantUnion[objectSize];
1140 for (size_t i = 0; i < objectSize; ++i)
1141 rightUnionArray[i] = *node->getUnionArrayPointer();
1142 returnType = getType();
1143 } else if (constantNode->getType().getObjectSize() > 1 && objectSize == 1) {
1144 // for a case like float f = vec4(2,3,4,5) + 1.2;
1145 unionArray = new ConstantUnion[constantNode->getType().getObjectSize()];
1146 for (size_t i = 0; i < constantNode->getType().getObjectSize(); ++i)
1147 unionArray[i] = *getUnionArrayPointer();
1148 returnType = node->getType();
1149 objectSize = constantNode->getType().getObjectSize();
1152 ConstantUnion* tempConstArray = 0;
1153 TIntermConstantUnion *tempNode;
1155 bool boolNodeFlag = false;
1158 tempConstArray = new ConstantUnion[objectSize];
1159 {// support MSVC++6.0
1160 for (size_t i = 0; i < objectSize; i++)
1161 tempConstArray[i] = unionArray[i] + rightUnionArray[i];
1165 tempConstArray = new ConstantUnion[objectSize];
1166 {// support MSVC++6.0
1167 for (size_t i = 0; i < objectSize; i++)
1168 tempConstArray[i] = unionArray[i] - rightUnionArray[i];
1173 case EOpVectorTimesScalar:
1174 case EOpMatrixTimesScalar:
1175 tempConstArray = new ConstantUnion[objectSize];
1176 {// support MSVC++6.0
1177 for (size_t i = 0; i < objectSize; i++)
1178 tempConstArray[i] = unionArray[i] * rightUnionArray[i];
1181 case EOpMatrixTimesMatrix:
1182 if (getType().getBasicType() != EbtFloat || node->getBasicType() != EbtFloat) {
1183 infoSink.info.message(EPrefixInternalError, getLine(), "Constant Folding cannot be done for matrix multiply");
1186 {// support MSVC++6.0
1187 int size = getNominalSize();
1188 tempConstArray = new ConstantUnion[size*size];
1189 for (int row = 0; row < size; row++) {
1190 for (int column = 0; column < size; column++) {
1191 tempConstArray[size * column + row].setFConst(0.0f);
1192 for (int i = 0; i < size; i++) {
1193 tempConstArray[size * column + row].setFConst(tempConstArray[size * column + row].getFConst() + unionArray[i * size + row].getFConst() * (rightUnionArray[column * size + i].getFConst()));
1200 tempConstArray = new ConstantUnion[objectSize];
1201 {// support MSVC++6.0
1202 for (size_t i = 0; i < objectSize; i++) {
1203 switch (getType().getBasicType()) {
1205 if (rightUnionArray[i] == 0.0f) {
1206 infoSink.info.message(EPrefixWarning, getLine(), "Divide by zero error during constant folding");
1207 tempConstArray[i].setFConst(unionArray[i].getFConst() < 0 ? -FLT_MAX : FLT_MAX);
1209 tempConstArray[i].setFConst(unionArray[i].getFConst() / rightUnionArray[i].getFConst());
1213 if (rightUnionArray[i] == 0) {
1214 infoSink.info.message(EPrefixWarning, getLine(), "Divide by zero error during constant folding");
1215 tempConstArray[i].setIConst(INT_MAX);
1217 tempConstArray[i].setIConst(unionArray[i].getIConst() / rightUnionArray[i].getIConst());
1220 infoSink.info.message(EPrefixInternalError, getLine(), "Constant folding cannot be done for \"/\"");
1227 case EOpMatrixTimesVector:
1228 if (node->getBasicType() != EbtFloat) {
1229 infoSink.info.message(EPrefixInternalError, getLine(), "Constant Folding cannot be done for matrix times vector");
1232 tempConstArray = new ConstantUnion[getNominalSize()];
1234 {// support MSVC++6.0
1235 for (int size = getNominalSize(), i = 0; i < size; i++) {
1236 tempConstArray[i].setFConst(0.0f);
1237 for (int j = 0; j < size; j++) {
1238 tempConstArray[i].setFConst(tempConstArray[i].getFConst() + ((unionArray[j*size + i].getFConst()) * rightUnionArray[j].getFConst()));
1243 tempNode = new TIntermConstantUnion(tempConstArray, node->getType());
1244 tempNode->setLine(getLine());
1248 case EOpVectorTimesMatrix:
1249 if (getType().getBasicType() != EbtFloat) {
1250 infoSink.info.message(EPrefixInternalError, getLine(), "Constant Folding cannot be done for vector times matrix");
1254 tempConstArray = new ConstantUnion[getNominalSize()];
1255 {// support MSVC++6.0
1256 for (int size = getNominalSize(), i = 0; i < size; i++) {
1257 tempConstArray[i].setFConst(0.0f);
1258 for (int j = 0; j < size; j++) {
1259 tempConstArray[i].setFConst(tempConstArray[i].getFConst() + ((unionArray[j].getFConst()) * rightUnionArray[i*size + j].getFConst()));
1265 case EOpLogicalAnd: // this code is written for possible future use, will not get executed currently
1266 tempConstArray = new ConstantUnion[objectSize];
1267 {// support MSVC++6.0
1268 for (size_t i = 0; i < objectSize; i++)
1269 tempConstArray[i] = unionArray[i] && rightUnionArray[i];
1273 case EOpLogicalOr: // this code is written for possible future use, will not get executed currently
1274 tempConstArray = new ConstantUnion[objectSize];
1275 {// support MSVC++6.0
1276 for (size_t i = 0; i < objectSize; i++)
1277 tempConstArray[i] = unionArray[i] || rightUnionArray[i];
1282 tempConstArray = new ConstantUnion[objectSize];
1283 {// support MSVC++6.0
1284 for (size_t i = 0; i < objectSize; i++)
1285 switch (getType().getBasicType()) {
1286 case EbtBool: tempConstArray[i].setBConst((unionArray[i] == rightUnionArray[i]) ? false : true); break;
1287 default: assert(false && "Default missing");
1293 assert(objectSize == 1);
1294 tempConstArray = new ConstantUnion[1];
1295 tempConstArray->setBConst(*unionArray < *rightUnionArray);
1296 returnType = TType(EbtBool, EbpUndefined, EvqConst);
1298 case EOpGreaterThan:
1299 assert(objectSize == 1);
1300 tempConstArray = new ConstantUnion[1];
1301 tempConstArray->setBConst(*unionArray > *rightUnionArray);
1302 returnType = TType(EbtBool, EbpUndefined, EvqConst);
1304 case EOpLessThanEqual:
1306 assert(objectSize == 1);
1307 ConstantUnion constant;
1308 constant.setBConst(*unionArray > *rightUnionArray);
1309 tempConstArray = new ConstantUnion[1];
1310 tempConstArray->setBConst(!constant.getBConst());
1311 returnType = TType(EbtBool, EbpUndefined, EvqConst);
1314 case EOpGreaterThanEqual:
1316 assert(objectSize == 1);
1317 ConstantUnion constant;
1318 constant.setBConst(*unionArray < *rightUnionArray);
1319 tempConstArray = new ConstantUnion[1];
1320 tempConstArray->setBConst(!constant.getBConst());
1321 returnType = TType(EbtBool, EbpUndefined, EvqConst);
1326 if (getType().getBasicType() == EbtStruct) {
1327 if (!CompareStructure(node->getType(), node->getUnionArrayPointer(), unionArray))
1328 boolNodeFlag = true;
1330 for (size_t i = 0; i < objectSize; i++) {
1331 if (unionArray[i] != rightUnionArray[i]) {
1332 boolNodeFlag = true;
1333 break; // break out of for loop
1338 tempConstArray = new ConstantUnion[1];
1339 if (!boolNodeFlag) {
1340 tempConstArray->setBConst(true);
1343 tempConstArray->setBConst(false);
1346 tempNode = new TIntermConstantUnion(tempConstArray, TType(EbtBool, EbpUndefined, EvqConst));
1347 tempNode->setLine(getLine());
1352 if (getType().getBasicType() == EbtStruct) {
1353 if (CompareStructure(node->getType(), node->getUnionArrayPointer(), unionArray))
1354 boolNodeFlag = true;
1356 for (size_t i = 0; i < objectSize; i++) {
1357 if (unionArray[i] == rightUnionArray[i]) {
1358 boolNodeFlag = true;
1359 break; // break out of for loop
1364 tempConstArray = new ConstantUnion[1];
1365 if (!boolNodeFlag) {
1366 tempConstArray->setBConst(true);
1369 tempConstArray->setBConst(false);
1372 tempNode = new TIntermConstantUnion(tempConstArray, TType(EbtBool, EbpUndefined, EvqConst));
1373 tempNode->setLine(getLine());
1378 infoSink.info.message(EPrefixInternalError, getLine(), "Invalid operator for constant folding");
1381 tempNode = new TIntermConstantUnion(tempConstArray, returnType);
1382 tempNode->setLine(getLine());
1387 // Do unary operations
1389 TIntermConstantUnion *newNode = 0;
1390 ConstantUnion* tempConstArray = new ConstantUnion[objectSize];
1391 for (size_t i = 0; i < objectSize; i++) {
1394 switch (getType().getBasicType()) {
1395 case EbtFloat: tempConstArray[i].setFConst(-unionArray[i].getFConst()); break;
1396 case EbtInt: tempConstArray[i].setIConst(-unionArray[i].getIConst()); break;
1398 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1402 case EOpLogicalNot: // this code is written for possible future use, will not get executed currently
1403 switch (getType().getBasicType()) {
1404 case EbtBool: tempConstArray[i].setBConst(!unionArray[i].getBConst()); break;
1406 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1414 newNode = new TIntermConstantUnion(tempConstArray, getType());
1415 newNode->setLine(getLine());
1420 TIntermTyped* TIntermediate::promoteConstantUnion(TBasicType promoteTo, TIntermConstantUnion* node)
1422 size_t size = node->getType().getObjectSize();
1424 ConstantUnion *leftUnionArray = new ConstantUnion[size];
1426 for (size_t i = 0; i < size; i++) {
1428 switch (promoteTo) {
1430 switch (node->getType().getBasicType()) {
1432 leftUnionArray[i].setFConst(static_cast<float>(node->getIConst(i)));
1435 leftUnionArray[i].setFConst(static_cast<float>(node->getBConst(i)));
1438 leftUnionArray[i].setFConst(static_cast<float>(node->getFConst(i)));
1441 infoSink.info.message(EPrefixInternalError, node->getLine(), "Cannot promote");
1446 switch (node->getType().getBasicType()) {
1448 leftUnionArray[i].setIConst(static_cast<int>(node->getIConst(i)));
1451 leftUnionArray[i].setIConst(static_cast<int>(node->getBConst(i)));
1454 leftUnionArray[i].setIConst(static_cast<int>(node->getFConst(i)));
1457 infoSink.info.message(EPrefixInternalError, node->getLine(), "Cannot promote");
1462 switch (node->getType().getBasicType()) {
1464 leftUnionArray[i].setBConst(node->getIConst(i) != 0);
1467 leftUnionArray[i].setBConst(node->getBConst(i));
1470 leftUnionArray[i].setBConst(node->getFConst(i) != 0.0f);
1473 infoSink.info.message(EPrefixInternalError, node->getLine(), "Cannot promote");
1479 infoSink.info.message(EPrefixInternalError, node->getLine(), "Incorrect data type found");
1485 const TType& t = node->getType();
1487 return addConstantUnion(leftUnionArray, TType(promoteTo, t.getPrecision(), t.getQualifier(), t.getNominalSize(), t.isMatrix(), t.isArray()), node->getLine());
1491 TString TIntermTraverser::hash(const TString& name, ShHashFunction64 hashFunction)
1493 if (hashFunction == NULL || name.empty())
1495 khronos_uint64_t number = (*hashFunction)(name.c_str(), name.length());
1496 TStringStream stream;
1497 stream << HASHED_NAME_PREFIX << std::hex << number;
1498 TString hashedName = stream.str();