diff options
Diffstat (limited to 'src/3rdparty/angle/src/compiler/translator/Intermediate.cpp')
-rw-r--r-- | src/3rdparty/angle/src/compiler/translator/Intermediate.cpp | 1915 |
1 files changed, 1013 insertions, 902 deletions
diff --git a/src/3rdparty/angle/src/compiler/translator/Intermediate.cpp b/src/3rdparty/angle/src/compiler/translator/Intermediate.cpp index 777cab5458..fa0c9f7748 100644 --- a/src/3rdparty/angle/src/compiler/translator/Intermediate.cpp +++ b/src/3rdparty/angle/src/compiler/translator/Intermediate.cpp @@ -1,5 +1,5 @@ // -// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved. +// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // @@ -16,110 +16,118 @@ #include "compiler/translator/localintermediate.h" #include "compiler/translator/QualifierAlive.h" #include "compiler/translator/RemoveTree.h" +#include "compiler/translator/SymbolTable.h" -bool CompareStructure(const TType& leftNodeType, ConstantUnion* rightUnionArray, ConstantUnion* leftUnionArray); +namespace +{ -static TPrecision GetHigherPrecision(TPrecision left, TPrecision right) +TPrecision GetHigherPrecision(TPrecision left, TPrecision right) { return left > right ? left : right; } -const char* getOperatorString(TOperator op) +bool ValidateMultiplication(TOperator op, const TType &left, const TType &right) { - switch (op) { - case EOpInitialize: return "="; - case EOpAssign: return "="; - case EOpAddAssign: return "+="; - case EOpSubAssign: return "-="; - case EOpDivAssign: return "/="; - - // Fall-through. - case EOpMulAssign: - case EOpVectorTimesMatrixAssign: - case EOpVectorTimesScalarAssign: - case EOpMatrixTimesScalarAssign: - case EOpMatrixTimesMatrixAssign: return "*="; - - // Fall-through. - case EOpIndexDirect: - case EOpIndexIndirect: return "[]"; - - case EOpIndexDirectStruct: return "."; - case EOpVectorSwizzle: return "."; - case EOpAdd: return "+"; - case EOpSub: return "-"; - case EOpMul: return "*"; - case EOpDiv: return "/"; - case EOpMod: UNIMPLEMENTED(); break; - case EOpEqual: return "=="; - case EOpNotEqual: return "!="; - case EOpLessThan: return "<"; - case EOpGreaterThan: return ">"; - case EOpLessThanEqual: return "<="; - case EOpGreaterThanEqual: return ">="; - - // Fall-through. + switch (op) + { + case EOpMul: + case EOpMulAssign: + return left.getNominalSize() == right.getNominalSize() && + left.getSecondarySize() == right.getSecondarySize(); case EOpVectorTimesScalar: + case EOpVectorTimesScalarAssign: + return true; case EOpVectorTimesMatrix: + return left.getNominalSize() == right.getRows(); + case EOpVectorTimesMatrixAssign: + return left.getNominalSize() == right.getRows() && + left.getNominalSize() == right.getCols(); case EOpMatrixTimesVector: + return left.getCols() == right.getNominalSize(); case EOpMatrixTimesScalar: - case EOpMatrixTimesMatrix: return "*"; - - case EOpLogicalOr: return "||"; - case EOpLogicalXor: return "^^"; - case EOpLogicalAnd: return "&&"; - case EOpNegative: return "-"; - case EOpVectorLogicalNot: return "not"; - case EOpLogicalNot: return "!"; - case EOpPostIncrement: return "++"; - case EOpPostDecrement: return "--"; - case EOpPreIncrement: return "++"; - case EOpPreDecrement: return "--"; - - // Fall-through. - case EOpConvIntToBool: - case EOpConvFloatToBool: return "bool"; - - // Fall-through. - case EOpConvBoolToFloat: - case EOpConvIntToFloat: return "float"; - - // Fall-through. - case EOpConvFloatToInt: - case EOpConvBoolToInt: return "int"; - - case EOpRadians: return "radians"; - case EOpDegrees: return "degrees"; - case EOpSin: return "sin"; - case EOpCos: return "cos"; - case EOpTan: return "tan"; - case EOpAsin: return "asin"; - case EOpAcos: return "acos"; - case EOpAtan: return "atan"; - case EOpExp: return "exp"; - case EOpLog: return "log"; - case EOpExp2: return "exp2"; - case EOpLog2: return "log2"; - case EOpSqrt: return "sqrt"; - case EOpInverseSqrt: return "inversesqrt"; - case EOpAbs: return "abs"; - case EOpSign: return "sign"; - case EOpFloor: return "floor"; - case EOpCeil: return "ceil"; - case EOpFract: return "fract"; - case EOpLength: return "length"; - case EOpNormalize: return "normalize"; - case EOpDFdx: return "dFdx"; - case EOpDFdy: return "dFdy"; - case EOpFwidth: return "fwidth"; - case EOpAny: return "any"; - case EOpAll: return "all"; - - default: break; + case EOpMatrixTimesScalarAssign: + return true; + case EOpMatrixTimesMatrix: + return left.getCols() == right.getRows(); + case EOpMatrixTimesMatrixAssign: + return left.getCols() == right.getCols() && + left.getRows() == right.getRows(); + + default: + UNREACHABLE(); + return false; + } +} + +bool CompareStructure(const TType& leftNodeType, + ConstantUnion *rightUnionArray, + ConstantUnion *leftUnionArray); + +bool CompareStruct(const TType &leftNodeType, + ConstantUnion *rightUnionArray, + ConstantUnion *leftUnionArray) +{ + const TFieldList &fields = leftNodeType.getStruct()->fields(); + + size_t structSize = fields.size(); + size_t index = 0; + + for (size_t j = 0; j < structSize; j++) + { + size_t size = fields[j]->type()->getObjectSize(); + for (size_t i = 0; i < size; i++) + { + if (fields[j]->type()->getBasicType() == EbtStruct) + { + if (!CompareStructure(*fields[j]->type(), + &rightUnionArray[index], + &leftUnionArray[index])) + { + return false; + } + } + else + { + if (leftUnionArray[index] != rightUnionArray[index]) + return false; + index++; + } + } } - return ""; + return true; } +bool CompareStructure(const TType &leftNodeType, + ConstantUnion *rightUnionArray, + ConstantUnion *leftUnionArray) +{ + if (leftNodeType.isArray()) + { + TType typeWithoutArrayness = leftNodeType; + typeWithoutArrayness.clearArrayness(); + + size_t arraySize = leftNodeType.getArraySize(); + + for (size_t i = 0; i < arraySize; ++i) + { + size_t offset = typeWithoutArrayness.getObjectSize() * i; + if (!CompareStruct(typeWithoutArrayness, + &rightUnionArray[offset], + &leftUnionArray[offset])) + { + return false; + } + } + } + else + { + return CompareStruct(leftNodeType, rightUnionArray, leftUnionArray); + } + return true; +} + +} // namespace anonymous + //////////////////////////////////////////////////////////////////////////// // // First set of functions are to help build the intermediate representation. @@ -133,9 +141,10 @@ const char* getOperatorString(TOperator op) // // Returns the added node. // -TIntermSymbol* TIntermediate::addSymbol(int id, const TString& name, const TType& type, const TSourceLoc& line) +TIntermSymbol *TIntermediate::addSymbol( + int id, const TString &name, const TType &type, const TSourceLoc &line) { - TIntermSymbol* node = new TIntermSymbol(id, name, type); + TIntermSymbol *node = new TIntermSymbol(id, name, type); node->setLine(line); return node; @@ -146,77 +155,71 @@ TIntermSymbol* TIntermediate::addSymbol(int id, const TString& name, const TType // // Returns the added node. // -TIntermTyped* TIntermediate::addBinaryMath(TOperator op, TIntermTyped* left, TIntermTyped* right, const TSourceLoc& line, TSymbolTable& symbolTable) +TIntermTyped *TIntermediate::addBinaryMath( + TOperator op, TIntermTyped *left, TIntermTyped *right, const TSourceLoc &line) { - switch (op) { - case EOpEqual: - case EOpNotEqual: - if (left->isArray()) - return 0; - break; - case EOpLessThan: - case EOpGreaterThan: - case EOpLessThanEqual: - case EOpGreaterThanEqual: - if (left->isMatrix() || left->isArray() || left->isVector() || left->getBasicType() == EbtStruct) { - return 0; - } - break; - case EOpLogicalOr: - case EOpLogicalXor: - case EOpLogicalAnd: - if (left->getBasicType() != EbtBool || left->isMatrix() || left->isArray() || left->isVector()) { - return 0; - } - break; - case EOpAdd: - case EOpSub: - case EOpDiv: - case EOpMul: - if (left->getBasicType() == EbtStruct || left->getBasicType() == EbtBool) - return 0; - default: break; + switch (op) + { + case EOpEqual: + case EOpNotEqual: + if (left->isArray()) + return NULL; + break; + case EOpLessThan: + case EOpGreaterThan: + case EOpLessThanEqual: + case EOpGreaterThanEqual: + if (left->isMatrix() || left->isArray() || left->isVector() || + left->getBasicType() == EbtStruct) + { + return NULL; + } + break; + case EOpLogicalOr: + case EOpLogicalXor: + case EOpLogicalAnd: + if (left->getBasicType() != EbtBool || + left->isMatrix() || left->isArray() || left->isVector()) + { + return NULL; + } + break; + case EOpAdd: + case EOpSub: + case EOpDiv: + case EOpMul: + if (left->getBasicType() == EbtStruct || left->getBasicType() == EbtBool) + return NULL; + default: + break; } - // - // First try converting the children to compatible types. - // - if (left->getType().getStruct() && right->getType().getStruct()) { - if (left->getType() != right->getType()) - return 0; - } else { - TIntermTyped* child = addConversion(op, left->getType(), right); - if (child) - right = child; - else { - child = addConversion(op, right->getType(), left); - if (child) - left = child; - else - return 0; - } + if (left->getBasicType() != right->getBasicType()) + { + return NULL; } // // Need a new node holding things together then. Make // one and promote it to the right type. // - TIntermBinary* node = new TIntermBinary(op); + TIntermBinary *node = new TIntermBinary(op); node->setLine(line); node->setLeft(left); node->setRight(right); - if (!node->promote(infoSink)) - return 0; + if (!node->promote(mInfoSink)) + return NULL; // // See if we can fold constants. // - TIntermTyped* typedReturnNode = 0; TIntermConstantUnion *leftTempConstant = left->getAsConstantUnion(); TIntermConstantUnion *rightTempConstant = right->getAsConstantUnion(); - if (leftTempConstant && rightTempConstant) { - typedReturnNode = leftTempConstant->fold(node->getOp(), rightTempConstant, infoSink); + if (leftTempConstant && rightTempConstant) + { + TIntermTyped *typedReturnNode = + leftTempConstant->fold(node->getOp(), rightTempConstant, mInfoSink); if (typedReturnNode) return typedReturnNode; @@ -230,23 +233,24 @@ TIntermTyped* TIntermediate::addBinaryMath(TOperator op, TIntermTyped* left, TIn // // Returns the added node. // -TIntermTyped* TIntermediate::addAssign(TOperator op, TIntermTyped* left, TIntermTyped* right, const TSourceLoc& line) +TIntermTyped *TIntermediate::addAssign( + TOperator op, TIntermTyped *left, TIntermTyped *right, const TSourceLoc &line) { - // - // Like adding binary math, except the conversion can only go - // from right to left. - // - TIntermBinary* node = new TIntermBinary(op); - node->setLine(line); + if (left->getType().getStruct() || right->getType().getStruct()) + { + if (left->getType() != right->getType()) + { + return NULL; + } + } - TIntermTyped* child = addConversion(op, left->getType(), right); - if (child == 0) - return 0; + TIntermBinary *node = new TIntermBinary(op); + node->setLine(line); node->setLeft(left); - node->setRight(child); - if (! node->promote(infoSink)) - return 0; + node->setRight(right); + if (!node->promote(mInfoSink)) + return NULL; return node; } @@ -258,9 +262,10 @@ TIntermTyped* TIntermediate::addAssign(TOperator op, TIntermTyped* left, TInterm // Returns the added node. // The caller should set the type of the returned node. // -TIntermTyped* TIntermediate::addIndex(TOperator op, TIntermTyped* base, TIntermTyped* index, const TSourceLoc& line) +TIntermTyped *TIntermediate::addIndex( + TOperator op, TIntermTyped *base, TIntermTyped *index, const TSourceLoc &line) { - TIntermBinary* node = new TIntermBinary(op); + TIntermBinary *node = new TIntermBinary(op); node->setLine(line); node->setLeft(base); node->setRight(index); @@ -275,65 +280,43 @@ TIntermTyped* TIntermediate::addIndex(TOperator op, TIntermTyped* base, TIntermT // // Returns the added node. // -TIntermTyped* TIntermediate::addUnaryMath(TOperator op, TIntermNode* childNode, const TSourceLoc& line, TSymbolTable& symbolTable) +TIntermTyped *TIntermediate::addUnaryMath( + TOperator op, TIntermNode *childNode, const TSourceLoc &line) { - TIntermUnary* node; - TIntermTyped* child = childNode->getAsTyped(); - - if (child == 0) { - infoSink.info.message(EPrefixInternalError, line, "Bad type in AddUnaryMath"); - return 0; - } - - switch (op) { - case EOpLogicalNot: - if (child->getType().getBasicType() != EbtBool || child->getType().isMatrix() || child->getType().isArray() || child->getType().isVector()) { - return 0; - } - break; - - case EOpPostIncrement: - case EOpPreIncrement: - case EOpPostDecrement: - case EOpPreDecrement: - case EOpNegative: - if (child->getType().getBasicType() == EbtStruct || child->getType().isArray()) - return 0; - default: break; - } - - // - // Do we need to promote the operand? - // - // Note: Implicit promotions were removed from the language. - // - TBasicType newType = EbtVoid; - switch (op) { - case EOpConstructInt: newType = EbtInt; break; - case EOpConstructBool: newType = EbtBool; break; - case EOpConstructFloat: newType = EbtFloat; break; - default: break; - } + TIntermUnary *node; + TIntermTyped *child = childNode->getAsTyped(); - if (newType != EbtVoid) { - child = addConversion(op, TType(newType, child->getPrecision(), EvqTemporary, - child->getNominalSize(), - child->isMatrix(), - child->isArray()), - child); - if (child == 0) - return 0; + if (child == NULL) + { + mInfoSink.info.message(EPrefixInternalError, line, + "Bad type in AddUnaryMath"); + return NULL; } - // - // For constructors, we are now done, it's all in the conversion. - // - switch (op) { - case EOpConstructInt: - case EOpConstructBool: - case EOpConstructFloat: - return child; - default: break; + switch (op) + { + case EOpLogicalNot: + if (child->getType().getBasicType() != EbtBool || + child->getType().isMatrix() || + child->getType().isArray() || + child->getType().isVector()) + { + return NULL; + } + break; + + case EOpPostIncrement: + case EOpPreIncrement: + case EOpPostDecrement: + case EOpPreDecrement: + case EOpNegative: + if (child->getType().getBasicType() == EbtStruct || + child->getType().isArray()) + { + return NULL; + } + default: + break; } TIntermConstantUnion *childTempConstant = 0; @@ -347,11 +330,12 @@ TIntermTyped* TIntermediate::addUnaryMath(TOperator op, TIntermNode* childNode, node->setLine(line); node->setOperand(child); - if (! node->promote(infoSink)) + if (!node->promote(mInfoSink)) return 0; - if (childTempConstant) { - TIntermTyped* newChild = childTempConstant->fold(op, 0, infoSink); + if (childTempConstant) + { + TIntermTyped *newChild = childTempConstant->fold(op, 0, mInfoSink); if (newChild) return newChild; @@ -370,24 +354,30 @@ TIntermTyped* TIntermediate::addUnaryMath(TOperator op, TIntermNode* childNode, // Returns an aggregate node, which could be the one passed in if // it was already an aggregate but no operator was set. // -TIntermAggregate* TIntermediate::setAggregateOperator(TIntermNode* node, TOperator op, const TSourceLoc& line) +TIntermAggregate *TIntermediate::setAggregateOperator( + TIntermNode *node, TOperator op, const TSourceLoc &line) { - TIntermAggregate* aggNode; + TIntermAggregate *aggNode; // // Make sure we have an aggregate. If not turn it into one. // - if (node) { + if (node) + { aggNode = node->getAsAggregate(); - if (aggNode == 0 || aggNode->getOp() != EOpNull) { + if (aggNode == NULL || aggNode->getOp() != EOpNull) + { // // Make an aggregate containing this node. // aggNode = new TIntermAggregate(); - aggNode->getSequence().push_back(node); + aggNode->getSequence()->push_back(node); } - } else + } + else + { aggNode = new TIntermAggregate(); + } // // Set the operator. @@ -399,148 +389,30 @@ TIntermAggregate* TIntermediate::setAggregateOperator(TIntermNode* node, TOperat } // -// Convert one type to another. -// -// Returns the node representing the conversion, which could be the same -// node passed in if no conversion was needed. -// -// Return 0 if a conversion can't be done. -// -TIntermTyped* TIntermediate::addConversion(TOperator op, const TType& type, TIntermTyped* node) -{ - // - // Does the base type allow operation? - // - switch (node->getBasicType()) { - case EbtVoid: - case EbtSampler2D: - case EbtSamplerCube: - return 0; - default: break; - } - - // - // Otherwise, if types are identical, no problem - // - if (type == node->getType()) - return node; - - // - // If one's a structure, then no conversions. - // - if (type.getStruct() || node->getType().getStruct()) - return 0; - - // - // If one's an array, then no conversions. - // - if (type.isArray() || node->getType().isArray()) - return 0; - - TBasicType promoteTo; - - switch (op) { - // - // Explicit conversions - // - case EOpConstructBool: - promoteTo = EbtBool; - break; - case EOpConstructFloat: - promoteTo = EbtFloat; - break; - case EOpConstructInt: - promoteTo = EbtInt; - break; - default: - // - // implicit conversions were removed from the language. - // - if (type.getBasicType() != node->getType().getBasicType()) - return 0; - // - // Size and structure could still differ, but that's - // handled by operator promotion. - // - return node; - } - - if (node->getAsConstantUnion()) { - - return (promoteConstantUnion(promoteTo, node->getAsConstantUnion())); - } else { - - // - // Add a new newNode for the conversion. - // - TIntermUnary* newNode = 0; - - TOperator newOp = EOpNull; - switch (promoteTo) { - case EbtFloat: - switch (node->getBasicType()) { - case EbtInt: newOp = EOpConvIntToFloat; break; - case EbtBool: newOp = EOpConvBoolToFloat; break; - default: - infoSink.info.message(EPrefixInternalError, node->getLine(), "Bad promotion node"); - return 0; - } - break; - case EbtBool: - switch (node->getBasicType()) { - case EbtInt: newOp = EOpConvIntToBool; break; - case EbtFloat: newOp = EOpConvFloatToBool; break; - default: - infoSink.info.message(EPrefixInternalError, node->getLine(), "Bad promotion node"); - return 0; - } - break; - case EbtInt: - switch (node->getBasicType()) { - case EbtBool: newOp = EOpConvBoolToInt; break; - case EbtFloat: newOp = EOpConvFloatToInt; break; - default: - infoSink.info.message(EPrefixInternalError, node->getLine(), "Bad promotion node"); - return 0; - } - break; - default: - infoSink.info.message(EPrefixInternalError, node->getLine(), "Bad promotion type"); - return 0; - } - - TType type(promoteTo, node->getPrecision(), EvqTemporary, node->getNominalSize(), node->isMatrix(), node->isArray()); - newNode = new TIntermUnary(newOp, type); - newNode->setLine(node->getLine()); - newNode->setOperand(node); - - return newNode; - } -} - -// // Safe way to combine two nodes into an aggregate. Works with null pointers, // a node that's not a aggregate yet, etc. // // Returns the resulting aggregate, unless 0 was passed in for // both existing nodes. // -TIntermAggregate* TIntermediate::growAggregate(TIntermNode* left, TIntermNode* right, const TSourceLoc& line) +TIntermAggregate *TIntermediate::growAggregate( + TIntermNode *left, TIntermNode *right, const TSourceLoc &line) { - if (left == 0 && right == 0) - return 0; + if (left == NULL && right == NULL) + return NULL; - TIntermAggregate* aggNode = 0; + TIntermAggregate *aggNode = NULL; if (left) aggNode = left->getAsAggregate(); - if (!aggNode || aggNode->getOp() != EOpNull) { + if (!aggNode || aggNode->getOp() != EOpNull) + { aggNode = new TIntermAggregate; if (left) - aggNode->getSequence().push_back(left); + aggNode->getSequence()->push_back(left); } if (right) - aggNode->getSequence().push_back(right); + aggNode->getSequence()->push_back(right); aggNode->setLine(line); @@ -550,15 +422,17 @@ TIntermAggregate* TIntermediate::growAggregate(TIntermNode* left, TIntermNode* r // // Turn an existing node into an aggregate. // -// Returns an aggregate, unless 0 was passed in for the existing node. +// Returns an aggregate, unless NULL was passed in for the existing node. // -TIntermAggregate* TIntermediate::makeAggregate(TIntermNode* node, const TSourceLoc& line) +TIntermAggregate *TIntermediate::makeAggregate( + TIntermNode *node, const TSourceLoc &line) { - if (node == 0) - return 0; + if (node == NULL) + return NULL; + + TIntermAggregate *aggNode = new TIntermAggregate; + aggNode->getSequence()->push_back(node); - TIntermAggregate* aggNode = new TIntermAggregate; - aggNode->getSequence().push_back(node); aggNode->setLine(line); return aggNode; @@ -571,32 +445,45 @@ TIntermAggregate* TIntermediate::makeAggregate(TIntermNode* node, const TSourceL // // Returns the selection node created. // -TIntermNode* TIntermediate::addSelection(TIntermTyped* cond, TIntermNodePair nodePair, const TSourceLoc& line) +TIntermNode *TIntermediate::addSelection( + TIntermTyped *cond, TIntermNodePair nodePair, const TSourceLoc &line) { // // For compile time constant selections, prune the code and // test now. // - if (cond->getAsTyped() && cond->getAsTyped()->getAsConstantUnion()) { + if (cond->getAsTyped() && cond->getAsTyped()->getAsConstantUnion()) + { if (cond->getAsConstantUnion()->getBConst(0) == true) - return nodePair.node1 ? setAggregateOperator(nodePair.node1, EOpSequence, nodePair.node1->getLine()) : NULL; + { + return nodePair.node1 ? setAggregateOperator( + nodePair.node1, EOpSequence, nodePair.node1->getLine()) : NULL; + } else - return nodePair.node2 ? setAggregateOperator(nodePair.node2, EOpSequence, nodePair.node2->getLine()) : NULL; + { + return nodePair.node2 ? setAggregateOperator( + nodePair.node2, EOpSequence, nodePair.node2->getLine()) : NULL; + } } - TIntermSelection* node = new TIntermSelection(cond, nodePair.node1, nodePair.node2); + TIntermSelection *node = new TIntermSelection( + cond, nodePair.node1, nodePair.node2); node->setLine(line); return node; } - -TIntermTyped* TIntermediate::addComma(TIntermTyped* left, TIntermTyped* right, const TSourceLoc& line) +TIntermTyped *TIntermediate::addComma( + TIntermTyped *left, TIntermTyped *right, const TSourceLoc &line) { - if (left->getType().getQualifier() == EvqConst && right->getType().getQualifier() == EvqConst) { + if (left->getType().getQualifier() == EvqConst && + right->getType().getQualifier() == EvqConst) + { return right; - } else { + } + else + { TIntermTyped *commaAggregate = growAggregate(left, right, line); commaAggregate->getAsAggregate()->setOp(EOpComma); commaAggregate->setType(right->getType()); @@ -612,27 +499,24 @@ TIntermTyped* TIntermediate::addComma(TIntermTyped* left, TIntermTyped* right, c // // Returns the selection node created, or 0 if one could not be. // -TIntermTyped* TIntermediate::addSelection(TIntermTyped* cond, TIntermTyped* trueBlock, TIntermTyped* falseBlock, const TSourceLoc& line) +TIntermTyped *TIntermediate::addSelection( + TIntermTyped *cond, TIntermTyped *trueBlock, TIntermTyped *falseBlock, + const TSourceLoc &line) { - // - // Get compatible types. - // - TIntermTyped* child = addConversion(EOpSequence, trueBlock->getType(), falseBlock); - if (child) - falseBlock = child; - else { - child = addConversion(EOpSequence, falseBlock->getType(), trueBlock); - if (child) - trueBlock = child; - else - return 0; + if (!cond || !trueBlock || !falseBlock || + trueBlock->getType() != falseBlock->getType()) + { + return NULL; } // // See if all the operands are constant, then fold it otherwise not. // - if (cond->getAsConstantUnion() && trueBlock->getAsConstantUnion() && falseBlock->getAsConstantUnion()) { + if (cond->getAsConstantUnion() && + trueBlock->getAsConstantUnion() && + falseBlock->getAsConstantUnion()) + { if (cond->getAsConstantUnion()->getBConst(0)) return trueBlock; else @@ -642,7 +526,8 @@ TIntermTyped* TIntermediate::addSelection(TIntermTyped* cond, TIntermTyped* true // // Make a selection node. // - TIntermSelection* node = new TIntermSelection(cond, trueBlock, falseBlock, trueBlock->getType()); + TIntermSelection *node = new TIntermSelection( + cond, trueBlock, falseBlock, trueBlock->getType()); node->getTypePointer()->setQualifier(EvqTemporary); node->setLine(line); @@ -655,29 +540,33 @@ TIntermTyped* TIntermediate::addSelection(TIntermTyped* cond, TIntermTyped* true // Returns the constant union node created. // -TIntermConstantUnion* TIntermediate::addConstantUnion(ConstantUnion* unionArrayPointer, const TType& t, const TSourceLoc& line) +TIntermConstantUnion *TIntermediate::addConstantUnion( + ConstantUnion *unionArrayPointer, const TType &t, const TSourceLoc &line) { - TIntermConstantUnion* node = new TIntermConstantUnion(unionArrayPointer, t); + TIntermConstantUnion *node = new TIntermConstantUnion(unionArrayPointer, t); node->setLine(line); return node; } -TIntermTyped* TIntermediate::addSwizzle(TVectorFields& fields, const TSourceLoc& line) +TIntermTyped *TIntermediate::addSwizzle( + TVectorFields &fields, const TSourceLoc &line) { - TIntermAggregate* node = new TIntermAggregate(EOpSequence); + TIntermAggregate *node = new TIntermAggregate(EOpSequence); node->setLine(line); - TIntermConstantUnion* constIntNode; - TIntermSequence &sequenceVector = node->getSequence(); - ConstantUnion* unionArray; + TIntermConstantUnion *constIntNode; + TIntermSequence *sequenceVector = node->getSequence(); + ConstantUnion *unionArray; - for (int i = 0; i < fields.num; i++) { + for (int i = 0; i < fields.num; i++) + { unionArray = new ConstantUnion[1]; unionArray->setIConst(fields.offsets[i]); - constIntNode = addConstantUnion(unionArray, TType(EbtInt, EbpUndefined, EvqConst), line); - sequenceVector.push_back(constIntNode); + constIntNode = addConstantUnion( + unionArray, TType(EbtInt, EbpUndefined, EvqConst), line); + sequenceVector->push_back(constIntNode); } return node; @@ -686,9 +575,11 @@ TIntermTyped* TIntermediate::addSwizzle(TVectorFields& fields, const TSourceLoc& // // Create loop nodes. // -TIntermNode* TIntermediate::addLoop(TLoopType type, TIntermNode* init, TIntermTyped* cond, TIntermTyped* expr, TIntermNode* body, const TSourceLoc& line) +TIntermNode *TIntermediate::addLoop( + TLoopType type, TIntermNode *init, TIntermTyped *cond, TIntermTyped *expr, + TIntermNode *body, const TSourceLoc &line) { - TIntermNode* node = new TIntermLoop(type, init, cond, expr, body); + TIntermNode *node = new TIntermLoop(type, init, cond, expr, body); node->setLine(line); return node; @@ -697,14 +588,16 @@ TIntermNode* TIntermediate::addLoop(TLoopType type, TIntermNode* init, TIntermTy // // Add branches. // -TIntermBranch* TIntermediate::addBranch(TOperator branchOp, const TSourceLoc& line) +TIntermBranch* TIntermediate::addBranch( + TOperator branchOp, const TSourceLoc &line) { return addBranch(branchOp, 0, line); } -TIntermBranch* TIntermediate::addBranch(TOperator branchOp, TIntermTyped* expression, const TSourceLoc& line) +TIntermBranch* TIntermediate::addBranch( + TOperator branchOp, TIntermTyped *expression, const TSourceLoc &line) { - TIntermBranch* node = new TIntermBranch(branchOp, expression); + TIntermBranch *node = new TIntermBranch(branchOp, expression); node->setLine(line); return node; @@ -714,15 +607,15 @@ TIntermBranch* TIntermediate::addBranch(TOperator branchOp, TIntermTyped* expres // This is to be executed once the final root is put on top by the parsing // process. // -bool TIntermediate::postProcess(TIntermNode* root) +bool TIntermediate::postProcess(TIntermNode *root) { - if (root == 0) + if (root == NULL) return true; // // First, finish off the top level sequence, if any // - TIntermAggregate* aggRoot = root->getAsAggregate(); + TIntermAggregate *aggRoot = root->getAsAggregate(); if (aggRoot && aggRoot->getOp() == EOpNull) aggRoot->setOp(EOpSequence); @@ -732,7 +625,7 @@ bool TIntermediate::postProcess(TIntermNode* root) // // This deletes the tree. // -void TIntermediate::remove(TIntermNode* root) +void TIntermediate::remove(TIntermNode *root) { if (root) RemoveAllTreeNodes(root); @@ -753,76 +646,149 @@ void TIntermediate::remove(TIntermNode* root) bool TIntermLoop::replaceChildNode( TIntermNode *original, TIntermNode *replacement) { - REPLACE_IF_IS(init, TIntermNode, original, replacement); - REPLACE_IF_IS(cond, TIntermTyped, original, replacement); - REPLACE_IF_IS(expr, TIntermTyped, original, replacement); - REPLACE_IF_IS(body, TIntermNode, original, replacement); + REPLACE_IF_IS(mInit, TIntermNode, original, replacement); + REPLACE_IF_IS(mCond, TIntermTyped, original, replacement); + REPLACE_IF_IS(mExpr, TIntermTyped, original, replacement); + REPLACE_IF_IS(mBody, TIntermNode, original, replacement); return false; } +void TIntermLoop::enqueueChildren(std::queue<TIntermNode *> *nodeQueue) const +{ + if (mInit) + { + nodeQueue->push(mInit); + } + if (mCond) + { + nodeQueue->push(mCond); + } + if (mExpr) + { + nodeQueue->push(mExpr); + } + if (mBody) + { + nodeQueue->push(mBody); + } +} + bool TIntermBranch::replaceChildNode( TIntermNode *original, TIntermNode *replacement) { - REPLACE_IF_IS(expression, TIntermTyped, original, replacement); + REPLACE_IF_IS(mExpression, TIntermTyped, original, replacement); return false; } +void TIntermBranch::enqueueChildren(std::queue<TIntermNode *> *nodeQueue) const +{ + if (mExpression) + { + nodeQueue->push(mExpression); + } +} + bool TIntermBinary::replaceChildNode( TIntermNode *original, TIntermNode *replacement) { - REPLACE_IF_IS(left, TIntermTyped, original, replacement); - REPLACE_IF_IS(right, TIntermTyped, original, replacement); + REPLACE_IF_IS(mLeft, TIntermTyped, original, replacement); + REPLACE_IF_IS(mRight, TIntermTyped, original, replacement); return false; } +void TIntermBinary::enqueueChildren(std::queue<TIntermNode *> *nodeQueue) const +{ + if (mLeft) + { + nodeQueue->push(mLeft); + } + if (mRight) + { + nodeQueue->push(mRight); + } +} + bool TIntermUnary::replaceChildNode( TIntermNode *original, TIntermNode *replacement) { - REPLACE_IF_IS(operand, TIntermTyped, original, replacement); + REPLACE_IF_IS(mOperand, TIntermTyped, original, replacement); return false; } +void TIntermUnary::enqueueChildren(std::queue<TIntermNode *> *nodeQueue) const +{ + if (mOperand) + { + nodeQueue->push(mOperand); + } +} + bool TIntermAggregate::replaceChildNode( TIntermNode *original, TIntermNode *replacement) { - for (size_t ii = 0; ii < sequence.size(); ++ii) + for (size_t ii = 0; ii < mSequence.size(); ++ii) { - REPLACE_IF_IS(sequence[ii], TIntermNode, original, replacement); + REPLACE_IF_IS(mSequence[ii], TIntermNode, original, replacement); } return false; } +void TIntermAggregate::enqueueChildren(std::queue<TIntermNode *> *nodeQueue) const +{ + for (size_t childIndex = 0; childIndex < mSequence.size(); childIndex++) + { + nodeQueue->push(mSequence[childIndex]); + } +} + bool TIntermSelection::replaceChildNode( TIntermNode *original, TIntermNode *replacement) { - REPLACE_IF_IS(condition, TIntermTyped, original, replacement); - REPLACE_IF_IS(trueBlock, TIntermNode, original, replacement); - REPLACE_IF_IS(falseBlock, TIntermNode, original, replacement); + REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement); + REPLACE_IF_IS(mTrueBlock, TIntermNode, original, replacement); + REPLACE_IF_IS(mFalseBlock, TIntermNode, original, replacement); return false; } +void TIntermSelection::enqueueChildren(std::queue<TIntermNode *> *nodeQueue) const +{ + if (mCondition) + { + nodeQueue->push(mCondition); + } + if (mTrueBlock) + { + nodeQueue->push(mTrueBlock); + } + if (mFalseBlock) + { + nodeQueue->push(mFalseBlock); + } +} + // // Say whether or not an operation node changes the value of a variable. // bool TIntermOperator::isAssignment() const { - switch (op) { - case EOpPostIncrement: - case EOpPostDecrement: - case EOpPreIncrement: - case EOpPreDecrement: - case EOpAssign: - case EOpAddAssign: - case EOpSubAssign: - case EOpMulAssign: - case EOpVectorTimesMatrixAssign: - case EOpVectorTimesScalarAssign: - case EOpMatrixTimesScalarAssign: - case EOpMatrixTimesMatrixAssign: - case EOpDivAssign: - return true; - default: - return false; + switch (mOp) + { + case EOpPostIncrement: + case EOpPostDecrement: + case EOpPreIncrement: + case EOpPreDecrement: + case EOpAssign: + case EOpAddAssign: + case EOpSubAssign: + case EOpMulAssign: + case EOpVectorTimesMatrixAssign: + case EOpVectorTimesScalarAssign: + case EOpMatrixTimesScalarAssign: + case EOpMatrixTimesMatrixAssign: + case EOpDivAssign: + return true; + default: + return false; } } @@ -831,26 +797,31 @@ bool TIntermOperator::isAssignment() const // bool TIntermOperator::isConstructor() const { - switch (op) { - case EOpConstructVec2: - case EOpConstructVec3: - case EOpConstructVec4: - case EOpConstructMat2: - case EOpConstructMat3: - case EOpConstructMat4: - case EOpConstructFloat: - case EOpConstructIVec2: - case EOpConstructIVec3: - case EOpConstructIVec4: - case EOpConstructInt: - case EOpConstructBVec2: - case EOpConstructBVec3: - case EOpConstructBVec4: - case EOpConstructBool: - case EOpConstructStruct: - return true; - default: - return false; + switch (mOp) + { + case EOpConstructVec2: + case EOpConstructVec3: + case EOpConstructVec4: + case EOpConstructMat2: + case EOpConstructMat3: + case EOpConstructMat4: + case EOpConstructFloat: + case EOpConstructIVec2: + case EOpConstructIVec3: + case EOpConstructIVec4: + case EOpConstructInt: + case EOpConstructUVec2: + case EOpConstructUVec3: + case EOpConstructUVec4: + case EOpConstructUInt: + case EOpConstructBVec2: + case EOpConstructBVec3: + case EOpConstructBVec4: + case EOpConstructBool: + case EOpConstructStruct: + return true; + default: + return false; } } @@ -860,35 +831,36 @@ bool TIntermOperator::isConstructor() const // // Returns false in nothing makes sense. // -bool TIntermUnary::promote(TInfoSink&) +bool TIntermUnary::promote(TInfoSink &) { - switch (op) { - case EOpLogicalNot: - if (operand->getBasicType() != EbtBool) - return false; - break; - case EOpNegative: - case EOpPostIncrement: - case EOpPostDecrement: - case EOpPreIncrement: - case EOpPreDecrement: - if (operand->getBasicType() == EbtBool) - return false; - break; + switch (mOp) + { + case EOpLogicalNot: + if (mOperand->getBasicType() != EbtBool) + return false; + break; + case EOpNegative: + case EOpPostIncrement: + case EOpPostDecrement: + case EOpPreIncrement: + case EOpPreDecrement: + if (mOperand->getBasicType() == EbtBool) + return false; + break; - // operators for built-ins are already type checked against their prototype - case EOpAny: - case EOpAll: - case EOpVectorLogicalNot: - return true; + // operators for built-ins are already type checked against their prototype + case EOpAny: + case EOpAll: + case EOpVectorLogicalNot: + return true; - default: - if (operand->getBasicType() != EbtFloat) - return false; + default: + if (mOperand->getBasicType() != EbtFloat) + return false; } - setType(operand->getType()); - type.setQualifier(EvqTemporary); + setType(mOperand->getType()); + mType.setQualifier(EvqTemporary); return true; } @@ -899,221 +871,260 @@ bool TIntermUnary::promote(TInfoSink&) // // Returns false if operator can't work on operands. // -bool TIntermBinary::promote(TInfoSink& infoSink) +bool TIntermBinary::promote(TInfoSink &infoSink) { // This function only handles scalars, vectors, and matrices. - if (left->isArray() || right->isArray()) { - infoSink.info.message(EPrefixInternalError, getLine(), "Invalid operation for arrays"); + if (mLeft->isArray() || mRight->isArray()) + { + infoSink.info.message(EPrefixInternalError, getLine(), + "Invalid operation for arrays"); return false; } // GLSL ES 2.0 does not support implicit type casting. // So the basic type should always match. - if (left->getBasicType() != right->getBasicType()) + if (mLeft->getBasicType() != mRight->getBasicType()) + { return false; + } // // Base assumption: just make the type the same as the left // operand. Then only deviations from this need be coded. // - setType(left->getType()); + setType(mLeft->getType()); // The result gets promoted to the highest precision. - TPrecision higherPrecision = GetHigherPrecision(left->getPrecision(), right->getPrecision()); + TPrecision higherPrecision = GetHigherPrecision( + mLeft->getPrecision(), mRight->getPrecision()); getTypePointer()->setPrecision(higherPrecision); // Binary operations results in temporary variables unless both // operands are const. - if (left->getQualifier() != EvqConst || right->getQualifier() != EvqConst) { + if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst) + { getTypePointer()->setQualifier(EvqTemporary); } - int size = std::max(left->getNominalSize(), right->getNominalSize()); + const int nominalSize = + std::max(mLeft->getNominalSize(), mRight->getNominalSize()); // - // All scalars. Code after this test assumes this case is removed! + // All scalars or structs. Code after this test assumes this case is removed! // - if (size == 1) { - switch (op) { - // - // Promote to conditional - // - case EOpEqual: - case EOpNotEqual: - case EOpLessThan: - case EOpGreaterThan: - case EOpLessThanEqual: - case EOpGreaterThanEqual: - setType(TType(EbtBool, EbpUndefined)); - break; + if (nominalSize == 1) + { + switch (mOp) + { + // + // Promote to conditional + // + case EOpEqual: + case EOpNotEqual: + case EOpLessThan: + case EOpGreaterThan: + case EOpLessThanEqual: + case EOpGreaterThanEqual: + setType(TType(EbtBool, EbpUndefined)); + break; - // - // And and Or operate on conditionals - // - case EOpLogicalAnd: - case EOpLogicalOr: - // Both operands must be of type bool. - if (left->getBasicType() != EbtBool || right->getBasicType() != EbtBool) - return false; - setType(TType(EbtBool, EbpUndefined)); - break; + // + // And and Or operate on conditionals + // + case EOpLogicalAnd: + case EOpLogicalOr: + // Both operands must be of type bool. + if (mLeft->getBasicType() != EbtBool || mRight->getBasicType() != EbtBool) + { + return false; + } + setType(TType(EbtBool, EbpUndefined)); + break; - default: - break; + default: + break; } return true; } // If we reach here, at least one of the operands is vector or matrix. // The other operand could be a scalar, vector, or matrix. - // Are the sizes compatible? - // - if (left->getNominalSize() != right->getNominalSize()) { - // If the nominal size of operands do not match: - // One of them must be scalar. - if (left->getNominalSize() != 1 && right->getNominalSize() != 1) - return false; - // Operator cannot be of type pure assignment. - if (op == EOpAssign || op == EOpInitialize) - return false; - } - - // // Can these two operands be combined? // - TBasicType basicType = left->getBasicType(); - switch (op) { - case EOpMul: - if (!left->isMatrix() && right->isMatrix()) { - if (left->isVector()) - op = EOpVectorTimesMatrix; - else { - op = EOpMatrixTimesScalar; - setType(TType(basicType, higherPrecision, EvqTemporary, size, true)); - } - } else if (left->isMatrix() && !right->isMatrix()) { - if (right->isVector()) { - op = EOpMatrixTimesVector; - setType(TType(basicType, higherPrecision, EvqTemporary, size, false)); - } else { - op = EOpMatrixTimesScalar; - } - } else if (left->isMatrix() && right->isMatrix()) { - op = EOpMatrixTimesMatrix; - } else if (!left->isMatrix() && !right->isMatrix()) { - if (left->isVector() && right->isVector()) { - // leave as component product - } else if (left->isVector() || right->isVector()) { - op = EOpVectorTimesScalar; - setType(TType(basicType, higherPrecision, EvqTemporary, size, false)); - } - } else { - infoSink.info.message(EPrefixInternalError, getLine(), "Missing elses"); - return false; + TBasicType basicType = mLeft->getBasicType(); + switch (mOp) + { + case EOpMul: + if (!mLeft->isMatrix() && mRight->isMatrix()) + { + if (mLeft->isVector()) + { + mOp = EOpVectorTimesMatrix; + setType(TType(basicType, higherPrecision, EvqTemporary, + mRight->getCols(), 1)); } - break; - case EOpMulAssign: - if (!left->isMatrix() && right->isMatrix()) { - if (left->isVector()) - op = EOpVectorTimesMatrixAssign; - else { - return false; - } - } else if (left->isMatrix() && !right->isMatrix()) { - if (right->isVector()) { - return false; - } else { - op = EOpMatrixTimesScalarAssign; - } - } else if (left->isMatrix() && right->isMatrix()) { - op = EOpMatrixTimesMatrixAssign; - } else if (!left->isMatrix() && !right->isMatrix()) { - if (left->isVector() && right->isVector()) { - // leave as component product - } else if (left->isVector() || right->isVector()) { - if (! left->isVector()) - return false; - op = EOpVectorTimesScalarAssign; - setType(TType(basicType, higherPrecision, EvqTemporary, size, false)); - } - } else { - infoSink.info.message(EPrefixInternalError, getLine(), "Missing elses"); - return false; + else + { + mOp = EOpMatrixTimesScalar; + setType(TType(basicType, higherPrecision, EvqTemporary, + mRight->getCols(), mRight->getRows())); } - break; + } + else if (mLeft->isMatrix() && !mRight->isMatrix()) + { + if (mRight->isVector()) + { + mOp = EOpMatrixTimesVector; + setType(TType(basicType, higherPrecision, EvqTemporary, + mLeft->getRows(), 1)); + } + else + { + mOp = EOpMatrixTimesScalar; + } + } + else if (mLeft->isMatrix() && mRight->isMatrix()) + { + mOp = EOpMatrixTimesMatrix; + setType(TType(basicType, higherPrecision, EvqTemporary, + mRight->getCols(), mLeft->getRows())); + } + else if (!mLeft->isMatrix() && !mRight->isMatrix()) + { + if (mLeft->isVector() && mRight->isVector()) + { + // leave as component product + } + else if (mLeft->isVector() || mRight->isVector()) + { + mOp = EOpVectorTimesScalar; + setType(TType(basicType, higherPrecision, EvqTemporary, + nominalSize, 1)); + } + } + else + { + infoSink.info.message(EPrefixInternalError, getLine(), + "Missing elses"); + return false; + } - case EOpAssign: - case EOpInitialize: - case EOpAdd: - case EOpSub: - case EOpDiv: - case EOpAddAssign: - case EOpSubAssign: - case EOpDivAssign: - if ((left->isMatrix() && right->isVector()) || - (left->isVector() && right->isMatrix())) + if (!ValidateMultiplication(mOp, mLeft->getType(), mRight->getType())) + { + return false; + } + break; + + case EOpMulAssign: + if (!mLeft->isMatrix() && mRight->isMatrix()) + { + if (mLeft->isVector()) + { + mOp = EOpVectorTimesMatrixAssign; + } + else + { return false; - setType(TType(basicType, higherPrecision, EvqTemporary, size, left->isMatrix() || right->isMatrix())); - break; - - case EOpEqual: - case EOpNotEqual: - case EOpLessThan: - case EOpGreaterThan: - case EOpLessThanEqual: - case EOpGreaterThanEqual: - if ((left->isMatrix() && right->isVector()) || - (left->isVector() && right->isMatrix())) + } + } + else if (mLeft->isMatrix() && !mRight->isMatrix()) + { + if (mRight->isVector()) + { return false; - setType(TType(EbtBool, EbpUndefined)); - break; - - default: - return false; - } - - return true; -} - -bool CompareStruct(const TType& leftNodeType, ConstantUnion* rightUnionArray, ConstantUnion* leftUnionArray) -{ - const TFieldList& fields = leftNodeType.getStruct()->fields(); - - size_t structSize = fields.size(); - size_t index = 0; - - for (size_t j = 0; j < structSize; j++) { - size_t size = fields[j]->type()->getObjectSize(); - for (size_t i = 0; i < size; i++) { - if (fields[j]->type()->getBasicType() == EbtStruct) { - if (!CompareStructure(*(fields[j]->type()), &rightUnionArray[index], &leftUnionArray[index])) - return false; - } else { - if (leftUnionArray[index] != rightUnionArray[index]) + } + else + { + mOp = EOpMatrixTimesScalarAssign; + } + } + else if (mLeft->isMatrix() && mRight->isMatrix()) + { + mOp = EOpMatrixTimesMatrixAssign; + setType(TType(basicType, higherPrecision, EvqTemporary, + mRight->getCols(), mLeft->getRows())); + } + else if (!mLeft->isMatrix() && !mRight->isMatrix()) + { + if (mLeft->isVector() && mRight->isVector()) + { + // leave as component product + } + else if (mLeft->isVector() || mRight->isVector()) + { + if (!mLeft->isVector()) return false; - index++; + mOp = EOpVectorTimesScalarAssign; + setType(TType(basicType, higherPrecision, EvqTemporary, + mLeft->getNominalSize(), 1)); } } - } - return true; -} + else + { + infoSink.info.message(EPrefixInternalError, getLine(), + "Missing elses"); + return false; + } -bool CompareStructure(const TType& leftNodeType, ConstantUnion* rightUnionArray, ConstantUnion* leftUnionArray) -{ - if (leftNodeType.isArray()) { - TType typeWithoutArrayness = leftNodeType; - typeWithoutArrayness.clearArrayness(); + if (!ValidateMultiplication(mOp, mLeft->getType(), mRight->getType())) + { + return false; + } + break; + + case EOpAssign: + case EOpInitialize: + case EOpAdd: + case EOpSub: + case EOpDiv: + case EOpAddAssign: + case EOpSubAssign: + case EOpDivAssign: + if ((mLeft->isMatrix() && mRight->isVector()) || + (mLeft->isVector() && mRight->isMatrix())) + { + return false; + } - size_t arraySize = leftNodeType.getArraySize(); + // Are the sizes compatible? + if (mLeft->getNominalSize() != mRight->getNominalSize() || + mLeft->getSecondarySize() != mRight->getSecondarySize()) + { + // If the nominal size of operands do not match: + // One of them must be scalar. + if (!mLeft->isScalar() && !mRight->isScalar()) + return false; - for (size_t i = 0; i < arraySize; ++i) { - size_t offset = typeWithoutArrayness.getObjectSize() * i; - if (!CompareStruct(typeWithoutArrayness, &rightUnionArray[offset], &leftUnionArray[offset])) + // Operator cannot be of type pure assignment. + if (mOp == EOpAssign || mOp == EOpInitialize) return false; } - } else - return CompareStruct(leftNodeType, rightUnionArray, leftUnionArray); + { + const int secondarySize = std::max( + mLeft->getSecondarySize(), mRight->getSecondarySize()); + setType(TType(basicType, higherPrecision, EvqTemporary, + nominalSize, secondarySize)); + } + break; + + case EOpEqual: + case EOpNotEqual: + case EOpLessThan: + case EOpGreaterThan: + case EOpLessThanEqual: + case EOpGreaterThanEqual: + if ((mLeft->getNominalSize() != mRight->getNominalSize()) || + (mLeft->getSecondarySize() != mRight->getSecondarySize())) + { + return false; + } + setType(TType(EbtBool, EbpUndefined)); + break; + + default: + return false; + } return true; } @@ -1123,372 +1134,472 @@ bool CompareStructure(const TType& leftNodeType, ConstantUnion* rightUnionArray, // // Returns the node to keep using, which may or may not be the node passed in. // - -TIntermTyped* TIntermConstantUnion::fold(TOperator op, TIntermTyped* constantNode, TInfoSink& infoSink) +TIntermTyped *TIntermConstantUnion::fold( + TOperator op, TIntermTyped *constantNode, TInfoSink &infoSink) { ConstantUnion *unionArray = getUnionArrayPointer(); + + if (!unionArray) + return NULL; + size_t objectSize = getType().getObjectSize(); - if (constantNode) { // binary operations + if (constantNode) + { + // binary operations TIntermConstantUnion *node = constantNode->getAsConstantUnion(); ConstantUnion *rightUnionArray = node->getUnionArrayPointer(); TType returnType = getType(); + if (!rightUnionArray) + return NULL; + // for a case like float f = 1.2 + vec4(2,3,4,5); - if (constantNode->getType().getObjectSize() == 1 && objectSize > 1) { + if (constantNode->getType().getObjectSize() == 1 && objectSize > 1) + { rightUnionArray = new ConstantUnion[objectSize]; for (size_t i = 0; i < objectSize; ++i) + { rightUnionArray[i] = *node->getUnionArrayPointer(); + } returnType = getType(); - } else if (constantNode->getType().getObjectSize() > 1 && objectSize == 1) { + } + else if (constantNode->getType().getObjectSize() > 1 && objectSize == 1) + { // for a case like float f = vec4(2,3,4,5) + 1.2; unionArray = new ConstantUnion[constantNode->getType().getObjectSize()]; for (size_t i = 0; i < constantNode->getType().getObjectSize(); ++i) + { unionArray[i] = *getUnionArrayPointer(); + } returnType = node->getType(); objectSize = constantNode->getType().getObjectSize(); } - ConstantUnion* tempConstArray = 0; + ConstantUnion *tempConstArray = NULL; TIntermConstantUnion *tempNode; bool boolNodeFlag = false; - switch(op) { - case EOpAdd: - tempConstArray = new ConstantUnion[objectSize]; - {// support MSVC++6.0 - for (size_t i = 0; i < objectSize; i++) - tempConstArray[i] = unionArray[i] + rightUnionArray[i]; - } - break; - case EOpSub: - tempConstArray = new ConstantUnion[objectSize]; - {// support MSVC++6.0 - for (size_t i = 0; i < objectSize; i++) - tempConstArray[i] = unionArray[i] - rightUnionArray[i]; - } - break; + switch(op) + { + case EOpAdd: + tempConstArray = new ConstantUnion[objectSize]; + for (size_t i = 0; i < objectSize; i++) + tempConstArray[i] = unionArray[i] + rightUnionArray[i]; + break; + case EOpSub: + tempConstArray = new ConstantUnion[objectSize]; + for (size_t i = 0; i < objectSize; i++) + tempConstArray[i] = unionArray[i] - rightUnionArray[i]; + break; - case EOpMul: - case EOpVectorTimesScalar: - case EOpMatrixTimesScalar: - tempConstArray = new ConstantUnion[objectSize]; - {// support MSVC++6.0 - for (size_t i = 0; i < objectSize; i++) - tempConstArray[i] = unionArray[i] * rightUnionArray[i]; - } - break; - case EOpMatrixTimesMatrix: - if (getType().getBasicType() != EbtFloat || node->getBasicType() != EbtFloat) { - infoSink.info.message(EPrefixInternalError, getLine(), "Constant Folding cannot be done for matrix multiply"); - return 0; + case EOpMul: + case EOpVectorTimesScalar: + case EOpMatrixTimesScalar: + tempConstArray = new ConstantUnion[objectSize]; + for (size_t i = 0; i < objectSize; i++) + tempConstArray[i] = unionArray[i] * rightUnionArray[i]; + break; + + case EOpMatrixTimesMatrix: + { + if (getType().getBasicType() != EbtFloat || + node->getBasicType() != EbtFloat) + { + infoSink.info.message( + EPrefixInternalError, getLine(), + "Constant Folding cannot be done for matrix multiply"); + return NULL; } - {// support MSVC++6.0 - int size = getNominalSize(); - tempConstArray = new ConstantUnion[size*size]; - for (int row = 0; row < size; row++) { - for (int column = 0; column < size; column++) { - tempConstArray[size * column + row].setFConst(0.0f); - for (int i = 0; i < size; i++) { - tempConstArray[size * column + row].setFConst(tempConstArray[size * column + row].getFConst() + unionArray[i * size + row].getFConst() * (rightUnionArray[column * size + i].getFConst())); - } + + const int leftCols = getCols(); + const int leftRows = getRows(); + const int rightCols = constantNode->getType().getCols(); + const int rightRows = constantNode->getType().getRows(); + const int resultCols = rightCols; + const int resultRows = leftRows; + + tempConstArray = new ConstantUnion[resultCols*resultRows]; + for (int row = 0; row < resultRows; row++) + { + for (int column = 0; column < resultCols; column++) + { + tempConstArray[resultRows * column + row].setFConst(0.0f); + for (int i = 0; i < leftCols; i++) + { + tempConstArray[resultRows * column + row].setFConst( + tempConstArray[resultRows * column + row].getFConst() + + unionArray[i * leftRows + row].getFConst() * + rightUnionArray[column * rightRows + i].getFConst()); } } } - break; - case EOpDiv: + + // update return type for matrix product + returnType.setPrimarySize(resultCols); + returnType.setSecondarySize(resultRows); + } + break; + + case EOpDiv: + { tempConstArray = new ConstantUnion[objectSize]; - {// support MSVC++6.0 - for (size_t i = 0; i < objectSize; i++) { - switch (getType().getBasicType()) { - case EbtFloat: - if (rightUnionArray[i] == 0.0f) { - infoSink.info.message(EPrefixWarning, getLine(), "Divide by zero error during constant folding"); - tempConstArray[i].setFConst(unionArray[i].getFConst() < 0 ? -FLT_MAX : FLT_MAX); - } else - tempConstArray[i].setFConst(unionArray[i].getFConst() / rightUnionArray[i].getFConst()); - break; + for (size_t i = 0; i < objectSize; i++) + { + switch (getType().getBasicType()) + { + case EbtFloat: + if (rightUnionArray[i] == 0.0f) + { + infoSink.info.message( + EPrefixWarning, getLine(), + "Divide by zero error during constant folding"); + tempConstArray[i].setFConst( + unionArray[i].getFConst() < 0 ? -FLT_MAX : FLT_MAX); + } + else + { + tempConstArray[i].setFConst( + unionArray[i].getFConst() / + rightUnionArray[i].getFConst()); + } + break; - case EbtInt: - if (rightUnionArray[i] == 0) { - infoSink.info.message(EPrefixWarning, getLine(), "Divide by zero error during constant folding"); - tempConstArray[i].setIConst(INT_MAX); - } else - tempConstArray[i].setIConst(unionArray[i].getIConst() / rightUnionArray[i].getIConst()); - break; - default: - infoSink.info.message(EPrefixInternalError, getLine(), "Constant folding cannot be done for \"/\""); - return 0; + case EbtInt: + if (rightUnionArray[i] == 0) + { + infoSink.info.message( + EPrefixWarning, getLine(), + "Divide by zero error during constant folding"); + tempConstArray[i].setIConst(INT_MAX); + } + else + { + tempConstArray[i].setIConst( + unionArray[i].getIConst() / + rightUnionArray[i].getIConst()); + } + break; + + case EbtUInt: + if (rightUnionArray[i] == 0) + { + infoSink.info.message( + EPrefixWarning, getLine(), + "Divide by zero error during constant folding"); + tempConstArray[i].setUConst(UINT_MAX); + } + else + { + tempConstArray[i].setUConst( + unionArray[i].getUConst() / + rightUnionArray[i].getUConst()); } + break; + + default: + infoSink.info.message( + EPrefixInternalError, getLine(), + "Constant folding cannot be done for \"/\""); + return NULL; } } - break; + } + break; - case EOpMatrixTimesVector: - if (node->getBasicType() != EbtFloat) { - infoSink.info.message(EPrefixInternalError, getLine(), "Constant Folding cannot be done for matrix times vector"); - return 0; + case EOpMatrixTimesVector: + { + if (node->getBasicType() != EbtFloat) + { + infoSink.info.message( + EPrefixInternalError, getLine(), + "Constant Folding cannot be done for matrix times vector"); + return NULL; } - tempConstArray = new ConstantUnion[getNominalSize()]; - {// support MSVC++6.0 - for (int size = getNominalSize(), i = 0; i < size; i++) { - tempConstArray[i].setFConst(0.0f); - for (int j = 0; j < size; j++) { - tempConstArray[i].setFConst(tempConstArray[i].getFConst() + ((unionArray[j*size + i].getFConst()) * rightUnionArray[j].getFConst())); - } + const int matrixCols = getCols(); + const int matrixRows = getRows(); + + tempConstArray = new ConstantUnion[matrixRows]; + + for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++) + { + tempConstArray[matrixRow].setFConst(0.0f); + for (int col = 0; col < matrixCols; col++) + { + tempConstArray[matrixRow].setFConst( + tempConstArray[matrixRow].getFConst() + + unionArray[col * matrixRows + matrixRow].getFConst() * + rightUnionArray[col].getFConst()); } } - tempNode = new TIntermConstantUnion(tempConstArray, node->getType()); + returnType = node->getType(); + returnType.setPrimarySize(matrixRows); + + tempNode = new TIntermConstantUnion(tempConstArray, returnType); tempNode->setLine(getLine()); return tempNode; + } - case EOpVectorTimesMatrix: - if (getType().getBasicType() != EbtFloat) { - infoSink.info.message(EPrefixInternalError, getLine(), "Constant Folding cannot be done for vector times matrix"); - return 0; + case EOpVectorTimesMatrix: + { + if (getType().getBasicType() != EbtFloat) + { + infoSink.info.message( + EPrefixInternalError, getLine(), + "Constant Folding cannot be done for vector times matrix"); + return NULL; } - tempConstArray = new ConstantUnion[getNominalSize()]; - {// support MSVC++6.0 - for (int size = getNominalSize(), i = 0; i < size; i++) { - tempConstArray[i].setFConst(0.0f); - for (int j = 0; j < size; j++) { - tempConstArray[i].setFConst(tempConstArray[i].getFConst() + ((unionArray[j].getFConst()) * rightUnionArray[i*size + j].getFConst())); - } + const int matrixCols = constantNode->getType().getCols(); + const int matrixRows = constantNode->getType().getRows(); + + tempConstArray = new ConstantUnion[matrixCols]; + + for (int matrixCol = 0; matrixCol < matrixCols; matrixCol++) + { + tempConstArray[matrixCol].setFConst(0.0f); + for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++) + { + tempConstArray[matrixCol].setFConst( + tempConstArray[matrixCol].getFConst() + + unionArray[matrixRow].getFConst() * + rightUnionArray[matrixCol * matrixRows + matrixRow].getFConst()); } } - break; - case EOpLogicalAnd: // this code is written for possible future use, will not get executed currently + returnType.setPrimarySize(matrixCols); + } + break; + + case EOpLogicalAnd: + // this code is written for possible future use, + // will not get executed currently + { tempConstArray = new ConstantUnion[objectSize]; - {// support MSVC++6.0 - for (size_t i = 0; i < objectSize; i++) - tempConstArray[i] = unionArray[i] && rightUnionArray[i]; + for (size_t i = 0; i < objectSize; i++) + { + tempConstArray[i] = unionArray[i] && rightUnionArray[i]; } - break; + } + break; - case EOpLogicalOr: // this code is written for possible future use, will not get executed currently + case EOpLogicalOr: + // this code is written for possible future use, + // will not get executed currently + { tempConstArray = new ConstantUnion[objectSize]; - {// support MSVC++6.0 - for (size_t i = 0; i < objectSize; i++) - tempConstArray[i] = unionArray[i] || rightUnionArray[i]; + for (size_t i = 0; i < objectSize; i++) + { + tempConstArray[i] = unionArray[i] || rightUnionArray[i]; } - break; + } + break; - case EOpLogicalXor: + case EOpLogicalXor: + { tempConstArray = new ConstantUnion[objectSize]; - {// support MSVC++6.0 - for (size_t i = 0; i < objectSize; i++) - switch (getType().getBasicType()) { - case EbtBool: tempConstArray[i].setBConst((unionArray[i] == rightUnionArray[i]) ? false : true); break; - default: assert(false && "Default missing"); + for (size_t i = 0; i < objectSize; i++) + { + switch (getType().getBasicType()) + { + case EbtBool: + tempConstArray[i].setBConst( + unionArray[i] == rightUnionArray[i] ? false : true); + break; + default: + UNREACHABLE(); + break; } } - break; + } + break; + + case EOpLessThan: + ASSERT(objectSize == 1); + tempConstArray = new ConstantUnion[1]; + tempConstArray->setBConst(*unionArray < *rightUnionArray); + returnType = TType(EbtBool, EbpUndefined, EvqConst); + break; - case EOpLessThan: - assert(objectSize == 1); + case EOpGreaterThan: + ASSERT(objectSize == 1); + tempConstArray = new ConstantUnion[1]; + tempConstArray->setBConst(*unionArray > *rightUnionArray); + returnType = TType(EbtBool, EbpUndefined, EvqConst); + break; + + case EOpLessThanEqual: + { + ASSERT(objectSize == 1); + ConstantUnion constant; + constant.setBConst(*unionArray > *rightUnionArray); tempConstArray = new ConstantUnion[1]; - tempConstArray->setBConst(*unionArray < *rightUnionArray); + tempConstArray->setBConst(!constant.getBConst()); returnType = TType(EbtBool, EbpUndefined, EvqConst); break; - case EOpGreaterThan: - assert(objectSize == 1); + } + + case EOpGreaterThanEqual: + { + ASSERT(objectSize == 1); + ConstantUnion constant; + constant.setBConst(*unionArray < *rightUnionArray); tempConstArray = new ConstantUnion[1]; - tempConstArray->setBConst(*unionArray > *rightUnionArray); + tempConstArray->setBConst(!constant.getBConst()); returnType = TType(EbtBool, EbpUndefined, EvqConst); break; - case EOpLessThanEqual: + } + + case EOpEqual: + if (getType().getBasicType() == EbtStruct) + { + if (!CompareStructure(node->getType(), + node->getUnionArrayPointer(), + unionArray)) { - assert(objectSize == 1); - ConstantUnion constant; - constant.setBConst(*unionArray > *rightUnionArray); - tempConstArray = new ConstantUnion[1]; - tempConstArray->setBConst(!constant.getBConst()); - returnType = TType(EbtBool, EbpUndefined, EvqConst); - break; + boolNodeFlag = true; } - case EOpGreaterThanEqual: + } + else + { + for (size_t i = 0; i < objectSize; i++) { - assert(objectSize == 1); - ConstantUnion constant; - constant.setBConst(*unionArray < *rightUnionArray); - tempConstArray = new ConstantUnion[1]; - tempConstArray->setBConst(!constant.getBConst()); - returnType = TType(EbtBool, EbpUndefined, EvqConst); - break; - } - - case EOpEqual: - if (getType().getBasicType() == EbtStruct) { - if (!CompareStructure(node->getType(), node->getUnionArrayPointer(), unionArray)) + if (unionArray[i] != rightUnionArray[i]) + { boolNodeFlag = true; - } else { - for (size_t i = 0; i < objectSize; i++) { - if (unionArray[i] != rightUnionArray[i]) { - boolNodeFlag = true; - break; // break out of for loop - } + break; // break out of for loop } } + } - tempConstArray = new ConstantUnion[1]; - if (!boolNodeFlag) { - tempConstArray->setBConst(true); - } - else { - tempConstArray->setBConst(false); - } + tempConstArray = new ConstantUnion[1]; + if (!boolNodeFlag) + { + tempConstArray->setBConst(true); + } + else + { + tempConstArray->setBConst(false); + } - tempNode = new TIntermConstantUnion(tempConstArray, TType(EbtBool, EbpUndefined, EvqConst)); - tempNode->setLine(getLine()); + tempNode = new TIntermConstantUnion( + tempConstArray, TType(EbtBool, EbpUndefined, EvqConst)); + tempNode->setLine(getLine()); - return tempNode; + return tempNode; - case EOpNotEqual: - if (getType().getBasicType() == EbtStruct) { - if (CompareStructure(node->getType(), node->getUnionArrayPointer(), unionArray)) + case EOpNotEqual: + if (getType().getBasicType() == EbtStruct) + { + if (CompareStructure(node->getType(), + node->getUnionArrayPointer(), + unionArray)) + { + boolNodeFlag = true; + } + } + else + { + for (size_t i = 0; i < objectSize; i++) + { + if (unionArray[i] == rightUnionArray[i]) + { boolNodeFlag = true; - } else { - for (size_t i = 0; i < objectSize; i++) { - if (unionArray[i] == rightUnionArray[i]) { - boolNodeFlag = true; - break; // break out of for loop - } + break; // break out of for loop } } + } - tempConstArray = new ConstantUnion[1]; - if (!boolNodeFlag) { - tempConstArray->setBConst(true); - } - else { - tempConstArray->setBConst(false); - } + tempConstArray = new ConstantUnion[1]; + if (!boolNodeFlag) + { + tempConstArray->setBConst(true); + } + else + { + tempConstArray->setBConst(false); + } - tempNode = new TIntermConstantUnion(tempConstArray, TType(EbtBool, EbpUndefined, EvqConst)); - tempNode->setLine(getLine()); + tempNode = new TIntermConstantUnion( + tempConstArray, TType(EbtBool, EbpUndefined, EvqConst)); + tempNode->setLine(getLine()); - return tempNode; + return tempNode; - default: - infoSink.info.message(EPrefixInternalError, getLine(), "Invalid operator for constant folding"); - return 0; + default: + infoSink.info.message( + EPrefixInternalError, getLine(), + "Invalid operator for constant folding"); + return NULL; } tempNode = new TIntermConstantUnion(tempConstArray, returnType); tempNode->setLine(getLine()); return tempNode; - } else { + } + else + { // // Do unary operations // TIntermConstantUnion *newNode = 0; ConstantUnion* tempConstArray = new ConstantUnion[objectSize]; - for (size_t i = 0; i < objectSize; i++) { - switch(op) { - case EOpNegative: - switch (getType().getBasicType()) { - case EbtFloat: tempConstArray[i].setFConst(-unionArray[i].getFConst()); break; - case EbtInt: tempConstArray[i].setIConst(-unionArray[i].getIConst()); break; - default: - infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant"); - return 0; - } + for (size_t i = 0; i < objectSize; i++) + { + switch(op) + { + case EOpNegative: + switch (getType().getBasicType()) + { + case EbtFloat: + tempConstArray[i].setFConst(-unionArray[i].getFConst()); break; - case EOpLogicalNot: // this code is written for possible future use, will not get executed currently - switch (getType().getBasicType()) { - case EbtBool: tempConstArray[i].setBConst(!unionArray[i].getBConst()); break; - default: - infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant"); - return 0; - } + case EbtInt: + tempConstArray[i].setIConst(-unionArray[i].getIConst()); break; - default: - return 0; - } - } - newNode = new TIntermConstantUnion(tempConstArray, getType()); - newNode->setLine(getLine()); - return newNode; - } -} - -TIntermTyped* TIntermediate::promoteConstantUnion(TBasicType promoteTo, TIntermConstantUnion* node) -{ - size_t size = node->getType().getObjectSize(); - - ConstantUnion *leftUnionArray = new ConstantUnion[size]; - - for (size_t i = 0; i < size; i++) { - - switch (promoteTo) { - case EbtFloat: - switch (node->getType().getBasicType()) { - case EbtInt: - leftUnionArray[i].setFConst(static_cast<float>(node->getIConst(i))); - break; - case EbtBool: - leftUnionArray[i].setFConst(static_cast<float>(node->getBConst(i))); - break; - case EbtFloat: - leftUnionArray[i].setFConst(static_cast<float>(node->getFConst(i))); - break; - default: - infoSink.info.message(EPrefixInternalError, node->getLine(), "Cannot promote"); - return 0; + case EbtUInt: + tempConstArray[i].setUConst(static_cast<unsigned int>( + -static_cast<int>(unionArray[i].getUConst()))); + break; + default: + infoSink.info.message( + EPrefixInternalError, getLine(), + "Unary operation not folded into constant"); + return NULL; } break; - case EbtInt: - switch (node->getType().getBasicType()) { - case EbtInt: - leftUnionArray[i].setIConst(static_cast<int>(node->getIConst(i))); - break; - case EbtBool: - leftUnionArray[i].setIConst(static_cast<int>(node->getBConst(i))); - break; - case EbtFloat: - leftUnionArray[i].setIConst(static_cast<int>(node->getFConst(i))); - break; - default: - infoSink.info.message(EPrefixInternalError, node->getLine(), "Cannot promote"); - return 0; + + case EOpLogicalNot: + // this code is written for possible future use, + // will not get executed currently + switch (getType().getBasicType()) + { + case EbtBool: + tempConstArray[i].setBConst(!unionArray[i].getBConst()); + break; + default: + infoSink.info.message( + EPrefixInternalError, getLine(), + "Unary operation not folded into constant"); + return NULL; } break; - case EbtBool: - switch (node->getType().getBasicType()) { - case EbtInt: - leftUnionArray[i].setBConst(node->getIConst(i) != 0); - break; - case EbtBool: - leftUnionArray[i].setBConst(node->getBConst(i)); - break; - case EbtFloat: - leftUnionArray[i].setBConst(node->getFConst(i) != 0.0f); - break; - default: - infoSink.info.message(EPrefixInternalError, node->getLine(), "Cannot promote"); - return 0; - } - break; - default: - infoSink.info.message(EPrefixInternalError, node->getLine(), "Incorrect data type found"); - return 0; + default: + return NULL; + } } - + newNode = new TIntermConstantUnion(tempConstArray, getType()); + newNode->setLine(getLine()); + return newNode; } - - const TType& t = node->getType(); - - return addConstantUnion(leftUnionArray, TType(promoteTo, t.getPrecision(), t.getQualifier(), t.getNominalSize(), t.isMatrix(), t.isArray()), node->getLine()); } // static -TString TIntermTraverser::hash(const TString& name, ShHashFunction64 hashFunction) +TString TIntermTraverser::hash(const TString &name, ShHashFunction64 hashFunction) { if (hashFunction == NULL || name.empty()) return name; |