diff options
Diffstat (limited to 'src/3rdparty/angle/src/compiler/translator/IntermNode.cpp')
-rw-r--r-- | src/3rdparty/angle/src/compiler/translator/IntermNode.cpp | 1107 |
1 files changed, 1107 insertions, 0 deletions
diff --git a/src/3rdparty/angle/src/compiler/translator/IntermNode.cpp b/src/3rdparty/angle/src/compiler/translator/IntermNode.cpp new file mode 100644 index 0000000000..b155545ad2 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/IntermNode.cpp @@ -0,0 +1,1107 @@ +// +// 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. +// + +// +// Build the intermediate representation. +// + +#include <float.h> +#include <limits.h> +#include <algorithm> + +#include "compiler/translator/HashNames.h" +#include "compiler/translator/IntermNode.h" +#include "compiler/translator/SymbolTable.h" + +namespace +{ + +TPrecision GetHigherPrecision(TPrecision left, TPrecision right) +{ + return left > right ? left : right; +} + +bool ValidateMultiplication(TOperator op, const TType &left, const TType &right) +{ + 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 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 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 + + +//////////////////////////////////////////////////////////////// +// +// Member functions of the nodes used for building the tree. +// +//////////////////////////////////////////////////////////////// + +#define REPLACE_IF_IS(node, type, original, replacement) \ + if (node == original) { \ + node = static_cast<type *>(replacement); \ + return true; \ + } + +bool TIntermLoop::replaceChildNode( + TIntermNode *original, TIntermNode *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(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(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(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 < mSequence.size(); ++ii) + { + 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(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 (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; + } +} + +// +// returns true if the operator is for one of the constructors +// +bool TIntermOperator::isConstructor() const +{ + 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; + } +} + +// +// Make sure the type of a unary operator is appropriate for its +// combination of operation and operand type. +// +// Returns false in nothing makes sense. +// +bool TIntermUnary::promote(TInfoSink &) +{ + 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; + + default: + if (mOperand->getBasicType() != EbtFloat) + return false; + } + + setType(mOperand->getType()); + mType.setQualifier(EvqTemporary); + + return true; +} + +// +// Establishes the type of the resultant operation, as well as +// makes the operator the correct one for the operands. +// +// Returns false if operator can't work on operands. +// +bool TIntermBinary::promote(TInfoSink &infoSink) +{ + // This function only handles scalars, vectors, and matrices. + 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 (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(mLeft->getType()); + + // The result gets promoted to the highest precision. + TPrecision higherPrecision = GetHigherPrecision( + mLeft->getPrecision(), mRight->getPrecision()); + getTypePointer()->setPrecision(higherPrecision); + + // Binary operations results in temporary variables unless both + // operands are const. + if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst) + { + getTypePointer()->setQualifier(EvqTemporary); + } + + const int nominalSize = + std::max(mLeft->getNominalSize(), mRight->getNominalSize()); + + // + // All scalars or structs. Code after this test assumes this case is removed! + // + 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 (mLeft->getBasicType() != EbtBool || mRight->getBasicType() != EbtBool) + { + return false; + } + setType(TType(EbtBool, EbpUndefined)); + 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. + // Can these two operands be combined? + // + 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)); + } + else + { + mOp = EOpMatrixTimesScalar; + setType(TType(basicType, higherPrecision, EvqTemporary, + mRight->getCols(), mRight->getRows())); + } + } + 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; + } + + 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; + } + } + else if (mLeft->isMatrix() && !mRight->isMatrix()) + { + if (mRight->isVector()) + { + return false; + } + 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; + mOp = EOpVectorTimesScalarAssign; + setType(TType(basicType, higherPrecision, EvqTemporary, + mLeft->getNominalSize(), 1)); + } + } + else + { + infoSink.info.message(EPrefixInternalError, getLine(), + "Missing elses"); + return false; + } + + 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; + } + + // 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; + + // Operator cannot be of type pure assignment. + if (mOp == EOpAssign || mOp == EOpInitialize) + return false; + } + + { + 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; +} + +// +// The fold functions see if an operation on a constant can be done in place, +// without generating run-time code. +// +// 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) +{ + ConstantUnion *unionArray = getUnionArrayPointer(); + + if (!unionArray) + return NULL; + + size_t objectSize = getType().getObjectSize(); + + 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) + { + 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) + { + // 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 = NULL; + TIntermConstantUnion *tempNode; + + bool boolNodeFlag = false; + 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]; + 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; + } + + 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()); + } + } + } + + // update return type for matrix product + returnType.setPrimarySize(resultCols); + returnType.setSecondarySize(resultRows); + } + break; + + case EOpDiv: + { + tempConstArray = new ConstantUnion[objectSize]; + 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; + + 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; + + case EOpMatrixTimesVector: + { + if (node->getBasicType() != EbtFloat) + { + infoSink.info.message( + EPrefixInternalError, getLine(), + "Constant Folding cannot be done for matrix times vector"); + return NULL; + } + + 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()); + } + } + + 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 NULL; + } + + 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()); + } + } + + returnType.setPrimarySize(matrixCols); + } + break; + + case EOpLogicalAnd: + // this code is written for possible future use, + // will not get executed currently + { + tempConstArray = new ConstantUnion[objectSize]; + for (size_t i = 0; i < objectSize; i++) + { + tempConstArray[i] = unionArray[i] && rightUnionArray[i]; + } + } + break; + + case EOpLogicalOr: + // this code is written for possible future use, + // will not get executed currently + { + tempConstArray = new ConstantUnion[objectSize]; + for (size_t i = 0; i < objectSize; i++) + { + tempConstArray[i] = unionArray[i] || rightUnionArray[i]; + } + } + break; + + case EOpLogicalXor: + { + tempConstArray = new ConstantUnion[objectSize]; + 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; + + case EOpLessThan: + ASSERT(objectSize == 1); + tempConstArray = new ConstantUnion[1]; + tempConstArray->setBConst(*unionArray < *rightUnionArray); + returnType = TType(EbtBool, EbpUndefined, EvqConst); + break; + + 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(!constant.getBConst()); + returnType = TType(EbtBool, EbpUndefined, EvqConst); + break; + } + + case EOpGreaterThanEqual: + { + 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)) + { + boolNodeFlag = true; + } + } + else + { + for (size_t i = 0; i < objectSize; i++) + { + if (unionArray[i] != rightUnionArray[i]) + { + boolNodeFlag = true; + break; // break out of for loop + } + } + } + + tempConstArray = new ConstantUnion[1]; + if (!boolNodeFlag) + { + tempConstArray->setBConst(true); + } + else + { + tempConstArray->setBConst(false); + } + + tempNode = new TIntermConstantUnion( + tempConstArray, TType(EbtBool, EbpUndefined, EvqConst)); + tempNode->setLine(getLine()); + + return tempNode; + + 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; + break; // break out of for loop + } + } + } + + tempConstArray = new ConstantUnion[1]; + if (!boolNodeFlag) + { + tempConstArray->setBConst(true); + } + else + { + tempConstArray->setBConst(false); + } + + tempNode = new TIntermConstantUnion( + tempConstArray, TType(EbtBool, EbpUndefined, EvqConst)); + tempNode->setLine(getLine()); + + return tempNode; + + default: + infoSink.info.message( + EPrefixInternalError, getLine(), + "Invalid operator for constant folding"); + return NULL; + } + tempNode = new TIntermConstantUnion(tempConstArray, returnType); + tempNode->setLine(getLine()); + + return tempNode; + } + 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; + 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 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; + + default: + return NULL; + } + } + newNode = new TIntermConstantUnion(tempConstArray, getType()); + newNode->setLine(getLine()); + return newNode; + } +} + +// static +TString TIntermTraverser::hash(const TString &name, ShHashFunction64 hashFunction) +{ + if (hashFunction == NULL || name.empty()) + return name; + khronos_uint64_t number = (*hashFunction)(name.c_str(), name.length()); + TStringStream stream; + stream << HASHED_NAME_PREFIX << std::hex << number; + TString hashedName = stream.str(); + return hashedName; +} |