From f4092abdf94af6a99aff944d6264bc1284e8bdd4 Mon Sep 17 00:00:00 2001 From: Reinhard Tartler Date: Mon, 10 Oct 2011 17:43:39 +0200 Subject: Imported nx-X11-3.1.0-1.tar.gz Summary: Imported nx-X11-3.1.0-1.tar.gz Keywords: Imported nx-X11-3.1.0-1.tar.gz into Git repository --- .../slang/MachineIndependent/Intermediate.cpp | 2110 ++++++++++++++++++++ 1 file changed, 2110 insertions(+) create mode 100755 nx-X11/extras/Mesa/src/mesa/shader/slang/MachineIndependent/Intermediate.cpp (limited to 'nx-X11/extras/Mesa/src/mesa/shader/slang/MachineIndependent/Intermediate.cpp') diff --git a/nx-X11/extras/Mesa/src/mesa/shader/slang/MachineIndependent/Intermediate.cpp b/nx-X11/extras/Mesa/src/mesa/shader/slang/MachineIndependent/Intermediate.cpp new file mode 100755 index 000000000..056fe17de --- /dev/null +++ b/nx-X11/extras/Mesa/src/mesa/shader/slang/MachineIndependent/Intermediate.cpp @@ -0,0 +1,2110 @@ +// +//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +//All rights reserved. +// +//Redistribution and use in source and binary forms, with or without +//modification, are permitted provided that the following conditions +//are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// +// Neither the name of 3Dlabs Inc. Ltd. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +//POSSIBILITY OF SUCH DAMAGE. +// + +// +// Build the intermediate representation. +// + +#include "../Include/ShHandle.h" +#include "localintermediate.h" +#include "QualifierAlive.h" +#include "RemoveTree.h" +#include + +//////////////////////////////////////////////////////////////////////////// +// +// First set of functions are to help build the intermediate representation. +// These functions are not member functions of the nodes. +// They are called from parser productions. +// +///////////////////////////////////////////////////////////////////////////// + +// +// Add a terminal node for an identifier in an expression. +// +// Returns the added node. +// +TIntermSymbol* TIntermediate::addSymbol(int id, const TString& name, const TType& type, TSourceLoc line) +{ + TIntermSymbol* node = new TIntermSymbol(id, name, type); + node->setLine(line); + + return node; +} + +// +// Connect two nodes with a new parent that does a binary operation on the nodes. +// +// Returns the added node. +// +TIntermTyped* TIntermediate::addBinaryMath(TOperator op, TIntermTyped* left, TIntermTyped* right, TSourceLoc line, TSymbolTable& symbolTable) +{ + switch (op) { + case EOpLessThan: + case EOpGreaterThan: + case EOpLessThanEqual: + case EOpGreaterThanEqual: + if (left->getType().isMatrix() || left->getType().isArray() || left->getType().isVector() || left->getType().getBasicType() == EbtStruct) { + return 0; + } + break; + case EOpLogicalOr: + case EOpLogicalXor: + case EOpLogicalAnd: + if (left->getType().getBasicType() != EbtBool || left->getType().isMatrix() || left->getType().isArray() || left->getType().isVector()) { + return 0; + } + break; + case EOpAdd: + case EOpSub: + case EOpDiv: + case EOpMul: + if (left->getType().getBasicType() == EbtStruct || left->getType().getBasicType() == EbtBool) + return 0; + default: break; + } + + // + // First try converting the children to compatible types. + // + + if (!(left->getType().getStruct() && right->getType().getStruct())) { + 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; + } + } else { + if (left->getType() != right->getType()) + return 0; + } + + + // + // Need a new node holding things together then. Make + // one and promote it to the right type. + // + TIntermBinary* node = new TIntermBinary(op); + if (line == 0) + line = right->getLine(); + node->setLine(line); + + node->setLeft(left); + node->setRight(right); + if (! node->promote(infoSink)) + return 0; + + TIntermConstantUnion *leftTempConstant = left->getAsConstantUnion(); + TIntermConstantUnion *rightTempConstant = right->getAsConstantUnion(); + + if (leftTempConstant) + leftTempConstant = copyConstUnion(left->getAsConstantUnion())->getAsConstantUnion(); + + if (rightTempConstant) + rightTempConstant = copyConstUnion(right->getAsConstantUnion())->getAsConstantUnion(); + + if (right->getType().getQualifier() == EvqConst && left->getType().getQualifier() == EvqConst) { + if (right->getAsAggregate()) { + rightTempConstant = changeAggrToTempConst(right->getAsAggregate(), symbolTable, line); + if (rightTempConstant->getUnionArrayPointer() == 0) + return 0; + } + + if (left->getAsAggregate()) { + leftTempConstant = changeAggrToTempConst(left->getAsAggregate(), symbolTable, line); + if (leftTempConstant->getUnionArrayPointer() == 0) + return 0; + } + } + + // + // See if we can fold constants. + // + + TIntermTyped* typedReturnNode = 0; + if ( leftTempConstant && rightTempConstant) { + if (leftTempConstant->getSize() == 1 && rightTempConstant->getSize() > 1) + typedReturnNode = rightTempConstant->fold(node->getOp(), leftTempConstant, infoSink, false); + else + typedReturnNode = leftTempConstant->fold(node->getOp(), rightTempConstant, infoSink, true); + + if (typedReturnNode) + return typedReturnNode; + else { + node->setLeft(leftTempConstant); + node->setRight(rightTempConstant); + } + } else if (leftTempConstant) { + node->setLeft(copyConstUnion(leftTempConstant)); + } else if (rightTempConstant) { + node->setRight(rightTempConstant); + } + + return node; +} + +// +// Connect two nodes through an assignment. +// +// Returns the added node. +// +TIntermTyped* TIntermediate::addAssign(TOperator op, TIntermTyped* left, TIntermTyped* right, TSourceLoc line) +{ + // + // Like adding binary math, except the conversion can only go + // from right to left. + // + TIntermBinary* node = new TIntermBinary(op); + if (line == 0) + line = left->getLine(); + node->setLine(line); + + if (right->getAsConstantUnion()) { // if the right node of assignment is a TempConstant node, allocate its own new space and remove the pointer to the symbol table value + right = copyConstUnion(right->getAsConstantUnion()) ; + if (right == 0) + return 0; + } + + TIntermTyped* child = addConversion(op, left->getType(), right); + if (child == 0) + return 0; + + node->setLeft(left); + node->setRight(child); + if (! node->promote(infoSink)) + return 0; + + return node; +} + +// +// Connect two nodes through an index operator, where the left node is the base +// of an array or struct, and the right node is a direct or indirect offset. +// +// Returns the added node. +// The caller should set the type of the returned node. +// +TIntermTyped* TIntermediate::addIndex(TOperator op, TIntermTyped* base, TIntermTyped* index, TSourceLoc line) +{ + TIntermBinary* node = new TIntermBinary(op); + if (line == 0) + line = index->getLine(); + node->setLine(line); + node->setLeft(base); + node->setRight(index); + + // caller should set the type + + return node; +} + +// +// Add one node as the parent of another that it operates on. +// +// Returns the added node. +// +TIntermTyped* TIntermediate::addUnaryMath(TOperator op, TIntermNode* childNode, TSourceLoc line, TSymbolTable& symbolTable) +{ + TIntermUnary* node; + TIntermTyped* child = childNode->getAsTyped(); + + if (child == 0) { + infoSink.info.message(EPrefixInternalError, "Bad type in AddUnaryMath", line); + 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) + 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; + } + + if (newType != EbtVoid) { + child = addConversion(op, TType(newType, EvqTemporary, child->getNominalSize(), + child->isMatrix(), + child->isArray()), + child); + if (child == 0) + return 0; + } + + // + // For constructors, we are now done, it's all in the conversion. + // + switch (op) { + case EOpConstructInt: + case EOpConstructBool: + case EOpConstructFloat: + return child; + default: break; + } + + if (child->getAsConstantUnion()) + child = copyConstUnion(child->getAsConstantUnion()); + + if (child->getAsAggregate() && child->getType().getQualifier() == EvqConst) { + child = changeAggrToTempConst(child->getAsAggregate(), symbolTable, line); + if (child->getAsConstantUnion()->getUnionArrayPointer() == 0) + return 0; + } + + TIntermConstantUnion *childTempConstant = child->getAsConstantUnion(); + + // + // Make a new node for the operator. + // + node = new TIntermUnary(op); + if (line == 0) + line = child->getLine(); + node->setLine(line); + node->setOperand(child); + + if (! node->promote(infoSink)) + return 0; + + if (childTempConstant) { + TIntermTyped* newChild = childTempConstant->fold(op, 0, infoSink, true); + + if (newChild) { + return newChild; + } + } + + return node; +} + +// +// This is the safe way to change the operator on an aggregate, as it +// does lots of error checking and fixing. Especially for establishing +// a function call's operation on it's set of parameters. Sequences +// of instructions are also aggregates, but they just direnctly set +// their operator to EOpSequence. +// +// Returns an aggregate node, which could be the one passed in if +// it was already an aggregate. +// +TIntermAggregate* TIntermediate::setAggregateOperator(TIntermNode* node, TOperator op, TSourceLoc line) +{ + TIntermAggregate* aggNode; + + // + // Make sure we have an aggregate. If not turn it into one. + // + if (node) { + aggNode = node->getAsAggregate(); + if (aggNode == 0 || aggNode->getOp() != EOpNull) { + // + // Make an aggregate containing this node. + // + aggNode = new TIntermAggregate(); + aggNode->getSequence().push_back(node); + if (line == 0) + line = node->getLine(); + } + } else + aggNode = new TIntermAggregate(); + + // + // Set the operator. + // + aggNode->setOperator(op); + if (line != 0) + aggNode->setLine(line); + + return aggNode; +} + +// +// 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 EbtSampler1D: + case EbtSampler2D: + case EbtSampler3D: + case EbtSamplerCube: + case EbtSampler1DShadow: + case EbtSampler2DShadow: + 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; + + 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; + } + + // + // Do conversion. + // + bool allConstant = true; + // check to see if there is an aggregate node + if (node->getAsAggregate()) { + if (node->getAsAggregate()->getOp() != EOpFunctionCall) { + // if the aggregate node is a constructor or a comma operator, look at its children, if they are constant + // convert them into the right type + TIntermSequence &sequenceVector = node->getAsAggregate()->getSequence() ; + for (TIntermSequence::iterator p = sequenceVector.begin(); + p != sequenceVector.end(); p++) { + if (!(*p)->getAsTyped()->getAsConstantUnion()) + allConstant = false; + } + } else + allConstant = false; + } + if (allConstant && node->getAsAggregate()) { // we can do the constant folding here as all the nodes of the aggregate are const + TIntermSequence &sequenceVector = node->getAsAggregate()->getSequence() ; + for (TIntermSequence::iterator p = sequenceVector.begin(); + p != sequenceVector.end(); p++) { + TIntermTyped* newNode = 0; + constUnion *unionArray = new constUnion[1]; + + switch (promoteTo) { + case EbtFloat: + switch ((*p)->getAsTyped()->getType().getBasicType()) { + + case EbtInt: + unionArray->fConst = static_cast((*p)->getAsTyped()->getAsConstantUnion()->getUnionArrayPointer()->iConst); + newNode = addConstantUnion(unionArray, TType(EbtFloat, EvqConst), node->getLine()); break; + case EbtBool: + unionArray->fConst = static_cast((*p)->getAsTyped()->getAsConstantUnion()->getUnionArrayPointer()->bConst); + newNode = newNode = addConstantUnion(unionArray, TType(EbtFloat, EvqConst), node->getLine()); break; + default: + infoSink.info.message(EPrefixInternalError, "Bad promotion node", node->getLine()); + return 0; + } + break; + case EbtInt: + switch ((*p)->getAsTyped()->getType().getBasicType()) { + case EbtFloat: + unionArray->iConst = static_cast((*p)->getAsTyped()->getAsConstantUnion()->getUnionArrayPointer()->fConst); + newNode = addConstantUnion(unionArray, TType(EbtInt, EvqConst), node->getLine()); + break; + case EbtBool: + unionArray->iConst = static_cast((*p)->getAsTyped()->getAsConstantUnion()->getUnionArrayPointer()->bConst); + newNode = addConstantUnion(unionArray, TType(EbtInt, EvqConst), node->getLine()); + break; + default: + infoSink.info.message(EPrefixInternalError, "Bad promotion node", node->getLine()); + return 0; + } + break; + case EbtBool: + switch ((*p)->getAsTyped()->getType().getBasicType()) { + case EbtFloat: + unionArray->bConst = (*p)->getAsTyped()->getAsConstantUnion()->getUnionArrayPointer()->fConst != 0.0 ; + newNode = addConstantUnion(unionArray, TType(EbtBool, EvqConst), node->getLine()); + break; + case EbtInt: + unionArray->bConst = (*p)->getAsTyped()->getAsConstantUnion()->getUnionArrayPointer()->iConst != 0 ; + newNode = addConstantUnion(unionArray, TType(EbtBool, EvqConst), node->getLine()); + break; + default: + infoSink.info.message(EPrefixInternalError, "Bad promotion node", node->getLine()); + return 0; + } + break; + default: + infoSink.info.message(EPrefixInternalError, "Bad promotion node", node->getLine()); + return 0; + } + if (newNode) { + sequenceVector.erase(p); + sequenceVector.insert(p, newNode); + } + } + return node->getAsAggregate(); + } else 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, "Bad promotion node", node->getLine()); + return 0; + } + break; + case EbtBool: + switch (node->getBasicType()) { + case EbtInt: newOp = EOpConvIntToBool; break; + case EbtFloat: newOp = EOpConvFloatToBool; break; + default: + infoSink.info.message(EPrefixInternalError, "Bad promotion node", node->getLine()); + return 0; + } + break; + case EbtInt: + switch (node->getBasicType()) { + case EbtBool: newOp = EOpConvBoolToInt; break; + case EbtFloat: newOp = EOpConvFloatToInt; break; + default: + infoSink.info.message(EPrefixInternalError, "Bad promotion node", node->getLine()); + return 0; + } + break; + default: + infoSink.info.message(EPrefixInternalError, "Bad promotion type", node->getLine()); + return 0; + } + + TType type(promoteTo, 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, TSourceLoc line) +{ + if (left == 0 && right == 0) + return 0; + + TIntermAggregate* aggNode = 0; + if (left) + aggNode = left->getAsAggregate(); + if (!aggNode || aggNode->getOp() != EOpNull) { + aggNode = new TIntermAggregate; + if (left) + aggNode->getSequence().push_back(left); + } + + if (right) + aggNode->getSequence().push_back(right); + + if (line != 0) + aggNode->setLine(line); + + return aggNode; +} + +// +// Turn an existing node into an aggregate. +// +// Returns an aggregate, unless 0 was passed in for the existing node. +// +TIntermAggregate* TIntermediate::makeAggregate(TIntermNode* node, TSourceLoc line) +{ + if (node == 0) + return 0; + + TIntermAggregate* aggNode = new TIntermAggregate; + aggNode->getSequence().push_back(node); + + if (line != 0) + aggNode->setLine(line); + else + aggNode->setLine(node->getLine()); + + return aggNode; +} + +// +// For "if" test nodes. There are three children; a condition, +// a true path, and a false path. The two paths are in the +// nodePair. +// +// Returns the selection node created. +// +TIntermNode* TIntermediate::addSelection(TIntermTyped* cond, TIntermNodePair nodePair, TSourceLoc line) +{ + // + // For compile time constant selections, prune the code and + // test now. + // + + if (cond->getAsTyped() && cond->getAsTyped()->getAsConstantUnion()) { + if (cond->getAsTyped()->getAsConstantUnion()->getUnionArrayPointer()->bConst) + return nodePair.node1; + else + return nodePair.node2; + } + + TIntermSelection* node = new TIntermSelection(cond, nodePair.node1, nodePair.node2); + node->setLine(line); + + return node; +} + + +TIntermTyped* TIntermediate::addComma(TIntermTyped* left, TIntermTyped* right, TSourceLoc line) +{ + if (left->getType().getQualifier() == EvqConst && right->getType().getQualifier() == EvqConst) { + return right; + } else { + TIntermTyped *commaAggregate = growAggregate(left, right, line); + commaAggregate->getAsAggregate()->setOperator(EOpComma); + commaAggregate->setType(right->getType()); + commaAggregate->getTypePointer()->changeQualifier(EvqTemporary); + return commaAggregate; + } +} + +// +// For "?:" test nodes. There are three children; a condition, +// a true path, and a false path. The two paths are specified +// as separate parameters. +// +// Returns the selection node created, or 0 if one could not be. +// +TIntermTyped* TIntermediate::addSelection(TIntermTyped* cond, TIntermTyped* trueBlock, TIntermTyped* falseBlock, 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; + } + + // + // See if condition is constant, and select now. + // + + if (cond->getAsConstantUnion()) { + if (cond->getAsConstantUnion()->getUnionArrayPointer()->bConst) + return trueBlock; + else + return falseBlock; + } + + // + // Make a selection node. + // + TIntermSelection* node = new TIntermSelection(cond, trueBlock, falseBlock, trueBlock->getType()); + node->setLine(line); + + return node; +} + +// +// Constant terminal nodes. Has a union that contains bool, float or int constants +// +// Returns the constant union node created. +// + +TIntermConstantUnion* TIntermediate::addConstantUnion(constUnion* unionArrayPointer, const TType& t, TSourceLoc line) +{ + TIntermConstantUnion* node = new TIntermConstantUnion(unionArrayPointer, t); + node->setLine(line); + + return node; +} + +TIntermTyped* TIntermediate::addSwizzle(TVectorFields& fields, TSourceLoc line) +{ + + TIntermAggregate* node = new TIntermAggregate(EOpSequence); + + node->setLine(line); + TIntermConstantUnion* constIntNode; + TIntermSequence &sequenceVector = node->getSequence(); + constUnion* unionArray; + + for (int i = 0; i < fields.num; i++) { + unionArray = new constUnion[1]; + unionArray->iConst = fields.offsets[i]; + constIntNode = addConstantUnion(unionArray, TType(EbtInt, EvqConst), line); + sequenceVector.push_back(constIntNode); + } + + return node; +} + +// +// Create loop nodes. +// +TIntermNode* TIntermediate::addLoop(TIntermNode* body, TIntermTyped* test, TIntermTyped* terminal, bool testFirst, TSourceLoc line) +{ + TIntermNode* node = new TIntermLoop(body, test, terminal, testFirst); + node->setLine(line); + + return node; +} + +// +// Add branches. +// +TIntermBranch* TIntermediate::addBranch(TOperator branchOp, TSourceLoc line) +{ + return addBranch(branchOp, 0, line); +} + +TIntermBranch* TIntermediate::addBranch(TOperator branchOp, TIntermTyped* expression, TSourceLoc line) +{ + TIntermBranch* node = new TIntermBranch(branchOp, expression); + node->setLine(line); + + return node; +} + +// +// This is to be executed once the final root is put on top by the parsing +// process. +// +bool TIntermediate::postProcess(TIntermNode* root, EShLanguage language) +{ + if (root == 0) + return true; + + // + // First, finish off the top level sequence, if any + // + TIntermAggregate* aggRoot = root->getAsAggregate(); + if (aggRoot && aggRoot->getOp() == EOpNull) + aggRoot->setOperator(EOpSequence); + + return true; +} + +// +// This deletes the tree. +// +void TIntermediate::remove(TIntermNode* root) +{ + if (root) + RemoveAllTreeNodes(root); +} + +//////////////////////////////////////////////////////////////// +// +// Member functions of the nodes used for building the tree. +// +//////////////////////////////////////////////////////////////// + +// +// Say whether or not an operation node changes the value of a variable. +// +// Returns true if state is modified. +// +bool TIntermOperator::modifiesState() 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: + case EOpModAssign: + case EOpAndAssign: + case EOpInclusiveOrAssign: + case EOpExclusiveOrAssign: + case EOpLeftShiftAssign: + case EOpRightShiftAssign: + return true; + default: + return false; + } +} + +// +// returns true if the operator is for one of the constructors +// +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; + } +} +// +// 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 (op) { + case EOpLogicalNot: + if (operand->getBasicType() != EbtBool) + return false; + break; + case EOpBitwiseNot: + if (operand->getBasicType() != EbtInt) + return false; + break; + case EOpNegative: + case EOpPostIncrement: + case EOpPostDecrement: + case EOpPreIncrement: + case EOpPreDecrement: + if (operand->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 (operand->getBasicType() != EbtFloat) + return false; + } + + setType(operand->getType()); + + 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) +{ + int size = left->getNominalSize(); + if (right->getNominalSize() > size) + size = right->getNominalSize(); + + TBasicType type = left->getBasicType(); + + // + // Don't operate on arrays. + // + if (left->isArray() || right->isArray()) + return false; + + // + // Base assumption: just make the type the same as the left + // operand. Then only deviations from this need be coded. + // + setType(TType(type, EvqTemporary, left->getNominalSize(), left->isMatrix())); + + // + // All scalars. 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)); + break; + + // + // And and Or operate on conditionals + // + case EOpLogicalAnd: + case EOpLogicalOr: + if (left->getBasicType() != EbtBool || right->getBasicType() != EbtBool) + return false; + setType(TType(EbtBool)); + break; + + // + // Check for integer only operands. + // + case EOpMod: + case EOpRightShift: + case EOpLeftShift: + case EOpAnd: + case EOpInclusiveOr: + case EOpExclusiveOr: + if (left->getBasicType() != EbtInt || right->getBasicType() != EbtInt) + return false; + break; + case EOpModAssign: + case EOpAndAssign: + case EOpInclusiveOrAssign: + case EOpExclusiveOrAssign: + case EOpLeftShiftAssign: + case EOpRightShiftAssign: + if (left->getBasicType() != EbtInt || right->getBasicType() != EbtInt) + return false; + // fall through + + // + // Everything else should have matching types + // + default: + if (left->getBasicType() != right->getBasicType() || + left->isMatrix() != right->isMatrix()) + return false; + } + + return true; + } + + // + // Are the sizes compatible? + // + if ( left->getNominalSize() != size && left->getNominalSize() != 1 || + right->getNominalSize() != size && right->getNominalSize() != 1) + return false; + + // + // Can these two operands be combined? + // + switch (op) { + case EOpMul: + if (!left->isMatrix() && right->isMatrix()) { + if (left->isVector()) + op = EOpVectorTimesMatrix; + else { + op = EOpMatrixTimesScalar; + setType(TType(type, EvqTemporary, size, true)); + } + } else if (left->isMatrix() && !right->isMatrix()) { + if (right->isVector()) { + op = EOpMatrixTimesVector; + setType(TType(type, 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(type, EvqTemporary, size, false)); + } + } else { + infoSink.info.message(EPrefixInternalError, "Missing elses", getLine()); + return false; + } + 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(type, EvqTemporary, size, false)); + } + } else { + infoSink.info.message(EPrefixInternalError, "Missing elses", getLine()); + return false; + } + break; + case EOpAssign: + if (left->getNominalSize() != right->getNominalSize()) + return false; + // fall through + case EOpAdd: + case EOpSub: + case EOpDiv: + case EOpMod: + case EOpAddAssign: + case EOpSubAssign: + case EOpDivAssign: + case EOpModAssign: + if (left->isMatrix() && right->isVector() || + left->isVector() && right->isMatrix() || + left->getBasicType() != right->getBasicType()) + return false; + setType(TType(type, 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() || + left->getBasicType() != right->getBasicType()) + return false; + setType(TType(EbtBool)); + break; + +default: + return false; + } + + // + // One more check for assignment. The Resulting type has to match the left operand. + // + switch (op) { + case EOpAssign: + case EOpAddAssign: + case EOpSubAssign: + case EOpMulAssign: + case EOpDivAssign: + case EOpModAssign: + case EOpAndAssign: + case EOpInclusiveOrAssign: + case EOpExclusiveOrAssign: + case EOpLeftShiftAssign: + case EOpRightShiftAssign: + if (getType() != left->getType()) + return false; + break; + default: + break; + } + + return true; +} + +bool compareStructure(const TType& leftNodeType, constUnion* rightUnionArray, constUnion* leftUnionArray, int& index) +{ + TTypeList* fields = leftNodeType.getStruct(); + + size_t structSize = fields->size(); + + for (size_t j = 0; j < structSize; j++) { + int size = (*fields)[j].type->getInstanceSize(); + for (int i = 0; i < size; i++) { + switch ((*fields)[j].type->getBasicType()) { + case EbtFloat: + if (leftUnionArray[index].fConst != rightUnionArray[index].fConst) + return false; + index++; + break; + case EbtInt: + if (leftUnionArray[index].iConst != rightUnionArray[index].iConst) + return false; + index++; + break; + case EbtBool: + if (leftUnionArray[index].bConst != rightUnionArray[index].bConst) + return false; + index++; + break; + case EbtStruct: + if (!compareStructure(*(*fields)[j].type, rightUnionArray, leftUnionArray, index)) + return false; + break; + default: + assert(true && "Cannot compare"); + break; + } + + } + } + 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, bool leftOperand) +{ + constUnion *unionArray = this->getUnionArrayPointer(); + + if (constantNode) { + if (constantNode->getAsConstantUnion() && constantNode->getSize() == 1 && constantNode->getType().getBasicType() != EbtStruct + && this->getSize() > 1) { + TIntermConstantUnion *node = constantNode->getAsConstantUnion(); + TIntermConstantUnion *newNode; + constUnion* tempConstArray; + switch(op) { + case EOpAdd: + tempConstArray = new constUnion[this->getSize()]; + {// support MSVC++6.0 + for (int i = 0; i < this->getSize(); i++) { + switch (this->getType().getBasicType()) { + case EbtFloat: tempConstArray[i].fConst = unionArray[i].fConst + node->getUnionArrayPointer()->fConst; break; + case EbtInt: tempConstArray[i].iConst = unionArray[i].iConst + node->getUnionArrayPointer()->iConst; break; + default: + infoSink.info.message(EPrefixInternalError, "Constant folding cannot be done for \"+\"", this->getLine()); + return 0; + } + } + } + break; + case EOpMatrixTimesScalar: + case EOpVectorTimesScalar: + tempConstArray = new constUnion[this->getSize()]; + {// support MSVC++6.0 + for (int i = 0; i < this->getSize(); i++) { + switch (this->getType().getBasicType()) { + case EbtFloat: tempConstArray[i].fConst = unionArray[i].fConst * node->getUnionArrayPointer()->fConst; break; + case EbtInt: tempConstArray[i].iConst = unionArray[i].iConst * node->getUnionArrayPointer()->iConst; break; + default: + infoSink.info.message(EPrefixInternalError, "Constant folding cannot be done for \"*\"", this->getLine()); + return 0; + } + } + } + break; + case EOpSub: + tempConstArray = new constUnion[this->getSize()]; + {// support MSVC++6.0 + for (int i = 0; i < this->getSize(); i++) { + switch (this->getType().getBasicType()) { + case EbtFloat: + if (leftOperand) + tempConstArray[i].fConst = unionArray[i].fConst - node->getUnionArrayPointer()->fConst; + else + tempConstArray[i].fConst = node->getUnionArrayPointer()->fConst - unionArray[i].fConst; + break; + + case EbtInt: + if (leftOperand) + tempConstArray[i].iConst = unionArray[i].iConst - node->getUnionArrayPointer()->iConst; + else + tempConstArray[i].iConst = node->getUnionArrayPointer()->iConst - unionArray[i].iConst; + break; + default: + infoSink.info.message(EPrefixInternalError, "Constant folding cannot be done for \"-\"", this->getLine()); + return 0; + } + } + } + break; + + case EOpDiv: + tempConstArray = new constUnion[this->getSize()]; + {// support MSVC++6.0 + for (int i = 0; i < this->getSize(); i++) { + switch (this->getType().getBasicType()) { + case EbtFloat: + if (leftOperand) { + if (node->getUnionArrayPointer()->fConst == 0.0) { + infoSink.info.message(EPrefixWarning, "Divide by zero error during constant folding", this->getLine()); + tempConstArray[i].fConst = FLT_MAX; + } else + tempConstArray[i].fConst = unionArray[i].fConst / node->getUnionArrayPointer()->fConst; + } else { + if (unionArray[i].fConst == 0.0) { + infoSink.info.message(EPrefixWarning, "Divide by zero error during constant folding", this->getLine()); + tempConstArray[i].fConst = FLT_MAX; + } else + tempConstArray[i].fConst = node->getUnionArrayPointer()->fConst / unionArray[i].fConst; + } + break; + + case EbtInt: + if (leftOperand) { + if (node->getUnionArrayPointer()->iConst == 0) { + infoSink.info.message(EPrefixWarning, "Divide by zero error during constant folding", this->getLine()); + tempConstArray[i].iConst = INT_MAX; + } else + tempConstArray[i].iConst = unionArray[i].iConst / node->getUnionArrayPointer()->iConst; + } else { + if (unionArray[i].iConst == 0) { + infoSink.info.message(EPrefixWarning, "Divide by zero error during constant folding", this->getLine()); + tempConstArray[i].iConst = INT_MAX; + } else + tempConstArray[i].iConst = node->getUnionArrayPointer()->iConst / unionArray[i].iConst; + } + break; + default: + infoSink.info.message(EPrefixInternalError, "Constant folding cannot be done for \"/\"", this->getLine()); + return 0; + } + } + } + break; + + case EOpLogicalAnd: // this code is written for possible future use, will not get executed currently + tempConstArray = new constUnion[this->getSize()]; + {// support MSVC++6.0 + for (int i = 0; i < this->getSize(); i++) { + switch (this->getType().getBasicType()) { + case EbtBool: tempConstArray[i].bConst = unionArray[i].bConst && node->getUnionArrayPointer()->bConst; break; + default: + infoSink.info.message(EPrefixInternalError, "Constant folding cannot be done for \"&&\"", this->getLine()); + return 0; + } + } + } + break; + + case EOpLogicalXor: // this code is written for possible future use, will not get executed currently + tempConstArray = new constUnion[this->getSize()]; + {// support MSVC++6.0 + for (int i = 0; i < this->getSize(); i++) { + switch (this->getType().getBasicType()) { + case EbtBool: tempConstArray[i].bConst = unionArray[i].bConst ^ node->getUnionArrayPointer()->bConst; break; + default: + infoSink.info.message(EPrefixInternalError, "Constant folding cannot be done for \"^^\"", this->getLine()); + return 0; + } + } + } + break; + + case EOpLogicalOr: // this code is written for possible future use, will not get executed currently + tempConstArray = new constUnion[this->getSize()]; + {// support MSVC++6.0 + for (int i = 0; i < this->getSize(); i++) { + switch (this->getType().getBasicType()) { + case EbtBool: tempConstArray[i].bConst = unionArray[i].bConst || node->getUnionArrayPointer()->bConst; break; + default: + infoSink.info.message(EPrefixInternalError, "Constant folding cannot be done for \"||\"", this->getLine()); + return 0; + } + } + } + break; + + default: + infoSink.info.message(EPrefixInternalError, "Invalid operator for constant folding", this->getLine()); + return 0; + } + newNode = new TIntermConstantUnion(tempConstArray, this->getType()); + newNode->setLine(this->getLine()); + + return newNode; + } else if (constantNode->getAsConstantUnion() && (this->getSize() > 1 || this->getType().getBasicType() == EbtStruct)) { + TIntermConstantUnion *node = constantNode->getAsConstantUnion(); + constUnion *rightUnionArray = node->getUnionArrayPointer(); + constUnion* tempConstArray = 0; + TIntermConstantUnion *tempNode; + int index = 0; + bool boolNodeFlag = false; + switch(op) { + case EOpAdd: + tempConstArray = new constUnion[this->getSize()]; + {// support MSVC++6.0 + for (int i = 0; i < this->getSize(); i++) { + switch (this->getType().getBasicType()) { + case EbtFloat: tempConstArray[i].fConst = unionArray[i].fConst + rightUnionArray[i].fConst; break; + case EbtInt: tempConstArray[i].iConst = unionArray[i].iConst + rightUnionArray[i].iConst; break; + default: + infoSink.info.message(EPrefixInternalError, "Constant folding cannot be done for \"+\"", this->getLine()); + return 0; + } + } + } + break; + case EOpSub: + tempConstArray = new constUnion[this->getSize()]; + {// support MSVC++6.0 + for (int i = 0; i < this->getSize(); i++) { + switch (this->getType().getBasicType()) { + case EbtFloat: + if (leftOperand) + tempConstArray[i].fConst = unionArray[i].fConst - rightUnionArray[i].fConst; + else + tempConstArray[i].fConst = rightUnionArray[i].fConst - unionArray[i].fConst; + break; + + case EbtInt: + if (leftOperand) + tempConstArray[i].iConst = unionArray[i].iConst - rightUnionArray[i].iConst; + else + tempConstArray[i].iConst = rightUnionArray[i].iConst - unionArray[i].iConst; + break; + + default: + infoSink.info.message(EPrefixInternalError, "Constant folding cannot be done for \"-\"", this->getLine()); + return 0; + } + } + } + break; + case EOpMul: + if (this->isVector()) { // two vectors multiplied together + int size = this->getSize(); + tempConstArray = new constUnion[size]; + + for (int i = 0; i < size; i++) { + switch (this->getType().getBasicType()) { + case EbtFloat: tempConstArray[i].fConst = unionArray[i].fConst * rightUnionArray[i].fConst; break; + case EbtInt: tempConstArray[i].iConst = unionArray[i].iConst * rightUnionArray[i].iConst; break; + default: + infoSink.info.message(EPrefixInternalError, "Constant folding cannot be done for vector multiply", this->getLine()); + return 0; + } + } + } + break; + case EOpMatrixTimesMatrix: + if (this->getType().getBasicType() != EbtFloat || node->getBasicType() != EbtFloat) { + infoSink.info.message(EPrefixInternalError, "Constant Folding cannot be done for matrix multiply", this->getLine()); + return 0; + } + {// support MSVC++6.0 + int size = this->getNominalSize(); + tempConstArray = new constUnion[size*size]; + for (int row = 0; row < size; row++) { + for (int column = 0; column < size; column++) { + tempConstArray[size * column + row].fConst = 0.0; + for (int i = 0; i < size; i++) { + tempConstArray[size * column + row].fConst += unionArray[i * size + row].fConst * (rightUnionArray[column * size + i].fConst); + } + } + } + } + break; + case EOpDiv: + tempConstArray = new constUnion[this->getSize()]; + {// support MSVC++6.0 + for (int i = 0; i < this->getSize(); i++) { + switch (this->getType().getBasicType()) { + case EbtFloat: + if (leftOperand) { + if (rightUnionArray[i].fConst == 0.0) { + infoSink.info.message(EPrefixWarning, "Divide by zero error during constant folding", this->getLine()); + tempConstArray[i].fConst = FLT_MAX; + } else + tempConstArray[i].fConst = unionArray[i].fConst / rightUnionArray[i].fConst; + } else { + if (unionArray[i].fConst == 0.0) { + infoSink.info.message(EPrefixWarning, "Divide by zero error during constant folding", this->getLine()); + tempConstArray[i].fConst = FLT_MAX; + } else + tempConstArray[i].fConst = rightUnionArray[i].fConst / unionArray[i].fConst; + } + break; + + case EbtInt: + if (leftOperand) { + if (rightUnionArray[i].iConst == 0) { + infoSink.info.message(EPrefixWarning, "Divide by zero error during constant folding", this->getLine()); + tempConstArray[i].iConst = INT_MAX; + } else + tempConstArray[i].iConst = unionArray[i].iConst / rightUnionArray[i].iConst; + } else { + if (unionArray[i].iConst == 0) { + infoSink.info.message(EPrefixWarning, "Divide by zero error during constant folding", this->getLine()); + tempConstArray[i].iConst = INT_MAX; + } else + tempConstArray[i].iConst = rightUnionArray[i].iConst / unionArray[i].iConst; + } + break; + default: + infoSink.info.message(EPrefixInternalError, "Constant folding cannot be done for \"/\"", this->getLine()); + return 0; + } + } + } + break; + + case EOpMatrixTimesVector: + if (node->getBasicType() != EbtFloat) { + infoSink.info.message(EPrefixInternalError, "Constant Folding cannot be done for matrix times vector", this->getLine()); + return 0; + } + tempConstArray = new constUnion[this->getNominalSize()]; + + {// support MSVC++6.0 + for (int size = this->getNominalSize(), i = 0; i < size; i++) { + tempConstArray[i].fConst = 0.0; + for (int j = 0; j < size; j++) { + tempConstArray[i].fConst += ((unionArray[j*size + i].fConst) * rightUnionArray[j].fConst); + } + } + } + + tempNode = new TIntermConstantUnion(tempConstArray, node->getType()); + tempNode->setLine(this->getLine()); + + return tempNode; + + case EOpVectorTimesMatrix: + if (this->getType().getBasicType() != EbtFloat) { + infoSink.info.message(EPrefixInternalError, "Constant Folding cannot be done for vector times matrix", this->getLine()); + return 0; + } + + tempConstArray = new constUnion[this->getNominalSize()]; + {// support MSVC++6.0 + for (int size = this->getNominalSize(), i = 0; i < size; i++) { + tempConstArray[i].fConst = 0.0; + for (int j = 0; j < size; j++) { + tempConstArray[i].fConst += ((unionArray[j].fConst) * rightUnionArray[i*size + j].fConst); + } + } + } + break; + + case EOpLogicalAnd: // this code is written for possible future use, will not get executed currently + tempConstArray = new constUnion[this->getSize()]; + {// support MSVC++6.0 + for (int i = 0; i < this->getSize(); i++) { + switch (this->getType().getBasicType()) { + case EbtBool: tempConstArray[i].bConst = unionArray[i].bConst && rightUnionArray[i].bConst; break; + default: + infoSink.info.message(EPrefixInternalError, "Constant folding cannot be done for \"&&\"", this->getLine()); + return 0; + } + } + } + break; + + case EOpLogicalXor: // this code is written for possible future use, will not get executed currently + tempConstArray = new constUnion[this->getSize()]; + {// support MSVC++6.0 + for (int i = 0; i < this->getSize(); i++) { + switch (this->getType().getBasicType()) { + case EbtBool: tempConstArray[i].bConst = unionArray[i].bConst ^ rightUnionArray[i].bConst; break; + default: + infoSink.info.message(EPrefixInternalError, "Constant folding cannot be done for \"^^\"", this->getLine()); + return 0; + } + } + } + break; + + case EOpLogicalOr: // this code is written for possible future use, will not get executed currently + tempConstArray = new constUnion[this->getSize()]; + {// support MSVC++6.0 + for (int i = 0; i < this->getSize(); i++) { + switch (this->getType().getBasicType()) { + case EbtBool: tempConstArray[i].bConst = unionArray[i].bConst || rightUnionArray[i].bConst; break; + default: + infoSink.info.message(EPrefixInternalError, "Constant folding cannot be done for \"||\"", this->getLine()); + return 0; + } + } + } + break; + + case EOpEqual: + + switch (this->getType().getBasicType()) { + case EbtFloat: + {// support MSVC++6.0 + for (int i = 0; i < this->getSize(); i++) { + if (unionArray[i].fConst != rightUnionArray[i].fConst) { + boolNodeFlag = true; + break; // break out of for loop + } + } + } + break; + + case EbtInt: + {// support MSVC++6.0 + for (int i = 0; i < this->getSize(); i++) { + if (unionArray[i].iConst != rightUnionArray[i].iConst) { + boolNodeFlag = true; + break; // break out of for loop + } + } + } + break; + case EbtBool: + {// support MSVC++6.0 + for (int i = 0; i < this->getSize(); i++) { + if (unionArray[i].bConst != rightUnionArray[i].bConst) { + boolNodeFlag = true; + break; // break out of for loop + } + } + } + break; + case EbtStruct: + if (!compareStructure(node->getType(), node->getUnionArrayPointer(), unionArray, index)) + boolNodeFlag = true; + break; + + default: + infoSink.info.message(EPrefixInternalError, "Constant folding cannot be done for \"==\"", this->getLine()); + return 0; + } + + tempConstArray = new constUnion[1]; + if (!boolNodeFlag) { + tempConstArray->bConst = true; + } + else { + tempConstArray->bConst = false; + } + + tempNode = new TIntermConstantUnion(tempConstArray, TType(EbtBool, EvqConst)); + tempNode->setLine(this->getLine()); + + return tempNode; + + case EOpNotEqual: + switch (this->getType().getBasicType()) { + case EbtFloat: + {// support MSVC++6.0 + for (int i = 0; i < this->getSize(); i++) { + if (unionArray[i].fConst == rightUnionArray[i].fConst) { + boolNodeFlag = true; + break; // break out of for loop + } + } + } + break; + + case EbtInt: + {// support MSVC++6.0 + for (int i = 0; i < this->getSize(); i++) { + if (unionArray[i].iConst == rightUnionArray[i].iConst) { + boolNodeFlag = true; + break; // break out of for loop + } + } + } + break; + case EbtBool: + {// support MSVC++6.0 + for (int i = 0; i < this->getSize(); i++) { + if (unionArray[i].bConst == rightUnionArray[i].bConst) { + boolNodeFlag = true; + break; // break out of for loop + } + } + } + break; + case EbtStruct: + if (compareStructure(node->getType(), node->getUnionArrayPointer(), unionArray, index)) + boolNodeFlag = true; + break; + default: + infoSink.info.message(EPrefixInternalError, "Constant folding cannot be done for \"!=\"", this->getLine()); + return 0; + } + + tempConstArray = new constUnion[1]; + if (!boolNodeFlag) { + tempConstArray->bConst = true; + } + else { + tempConstArray->bConst = false; + } + + tempNode = new TIntermConstantUnion(tempConstArray, TType(EbtBool, EvqConst)); + tempNode->setLine(this->getLine()); + + return tempNode; + + default: + infoSink.info.message(EPrefixInternalError, "Invalid operator for constant folding", this->getLine()); + return 0; + } + tempNode = new TIntermConstantUnion(tempConstArray, this->getType()); + tempNode->setLine(this->getLine()); + + return tempNode; + } else if (this->getSize() == 1 && this->getType().getBasicType() != EbtStruct + && constantNode->getSize() == 1 && constantNode->getType().getBasicType() != EbtStruct ) { // scalar constant folding + constUnion *unionArray = new constUnion[1]; + TIntermConstantUnion* newNode = 0; + + switch (this->getType().getBasicType()) { + case EbtInt: + { + // + // Dealing with two operands, us and constant. + // + // Do Binary operations. + // + int rightValue = constantNode->getAsConstantUnion()->getUnionArrayPointer()->iConst; + int leftValue = this->getUnionArrayPointer()->iConst; + //int line = this->getLine(); + + switch(op) { + //?? add constant intrinsics + case EOpAdd: unionArray->iConst = leftValue + rightValue; break; + case EOpSub: unionArray->iConst = leftValue - rightValue; break; + case EOpMul: unionArray->iConst = leftValue * rightValue; break; + case EOpDiv: + if (rightValue == 0) { + infoSink.info.message(EPrefixWarning, "Divide by zero error during constant folding", this->getLine()); + unionArray->iConst = INT_MAX; + } else + unionArray->iConst = leftValue / rightValue; break; + + case EOpMod: unionArray->iConst = leftValue % rightValue; break; + + case EOpRightShift: unionArray->iConst = leftValue >> rightValue; break; + case EOpLeftShift: unionArray->iConst = leftValue << rightValue; break; + + case EOpAnd: unionArray->iConst = leftValue & rightValue; break; + case EOpInclusiveOr: unionArray->iConst = leftValue | rightValue; break; + case EOpExclusiveOr: unionArray->iConst = leftValue ^ rightValue; break; + + // the following assume it's okay to have memory leaks + case EOpEqual: + unionArray->bConst = leftValue == rightValue; + newNode = new TIntermConstantUnion(unionArray, TType(EbtBool, EvqConst)); + break; + case EOpNotEqual: + unionArray->bConst = leftValue != rightValue; + newNode = new TIntermConstantUnion(unionArray, TType(EbtBool, EvqConst)); + break; + case EOpLessThan: + unionArray->bConst = leftValue < rightValue; + newNode = new TIntermConstantUnion(unionArray, TType(EbtBool, EvqConst)); + break; + case EOpGreaterThan: + unionArray->bConst = leftValue > rightValue; + newNode = new TIntermConstantUnion(unionArray, TType(EbtBool, EvqConst)); + break; + case EOpLessThanEqual: + unionArray->bConst = leftValue <= rightValue; + newNode = new TIntermConstantUnion(unionArray, TType(EbtBool, EvqConst)); + break; + case EOpGreaterThanEqual: + unionArray->bConst = leftValue >= rightValue; + newNode = new TIntermConstantUnion(unionArray, TType(EbtBool, EvqConst)); + break; + + default: + //infoSink.info.message(EPrefixInternalError, "Binary operation not folded into constant int", line); + return 0; + } + if (!newNode) { + newNode = new TIntermConstantUnion(unionArray, TType(EbtInt, EvqConst)); + } + newNode->setLine(constantNode->getLine()); + return newNode; + } + case EbtFloat: + { + float rightValue = constantNode->getAsConstantUnion()->getUnionArrayPointer()->fConst; + float leftValue = this->getUnionArrayPointer()->fConst; + + switch(op) { + //?? add constant intrinsics + case EOpAdd: unionArray->fConst = leftValue + rightValue; break; + case EOpSub: unionArray->fConst = leftValue - rightValue; break; + case EOpMul: unionArray->fConst = leftValue * rightValue; break; + case EOpDiv: + if (rightValue == 0.0) { + infoSink.info.message(EPrefixWarning, "Divide by zero error during constant folding", this->getLine()); + unionArray->fConst = FLT_MAX; + } else + unionArray->fConst = leftValue / rightValue; break; + + // the following assume it's okay to have memory leaks (cleaned up by pool allocator) + case EOpEqual: + unionArray->bConst = leftValue == rightValue; + newNode = new TIntermConstantUnion(unionArray, TType(EbtBool, EvqConst)); + break; + case EOpNotEqual: + unionArray->bConst = leftValue != rightValue; + newNode = new TIntermConstantUnion(unionArray, TType(EbtBool, EvqConst)); + break; + case EOpLessThan: + unionArray->bConst = leftValue < rightValue; + newNode = new TIntermConstantUnion(unionArray, TType(EbtBool, EvqConst)); + break; + case EOpGreaterThan: + unionArray->bConst = leftValue > rightValue; + newNode = new TIntermConstantUnion(unionArray, TType(EbtBool, EvqConst)); + break; + case EOpLessThanEqual: + unionArray->bConst = leftValue <= rightValue; + newNode = new TIntermConstantUnion(unionArray, TType(EbtBool, EvqConst)); + break; + case EOpGreaterThanEqual: + unionArray->bConst = leftValue >= rightValue; + newNode = new TIntermConstantUnion(unionArray, TType(EbtBool, EvqConst)); + break; + + default: + //infoSink.info.message(EPrefixInternalError, "Binary operation not folded into constant float", line); + return 0; + } + if (!newNode) { + newNode = new TIntermConstantUnion(unionArray, TType(EbtFloat, EvqConst)); + } + newNode->setLine(constantNode->getLine()); + return newNode; + } + case EbtBool: + { + bool rightValue = constantNode->getAsConstantUnion()->getUnionArrayPointer()->bConst; + bool leftValue = this->getUnionArrayPointer()->bConst; + + switch(op) { + //?? add constant intrinsics + case EOpLogicalAnd: unionArray->bConst = leftValue & rightValue; break; + case EOpLogicalXor: unionArray->bConst = leftValue ^ rightValue; break; + case EOpLogicalOr: unionArray->bConst = leftValue | rightValue; break; + default: + infoSink.info.message(EPrefixInternalError, "Binary operator cannot be folded into constant bool", line); + return 0; + } + newNode = new TIntermConstantUnion(unionArray, TType(EbtBool, EvqConst)); + newNode->setLine(constantNode->getLine()); + return newNode; + } + default: + infoSink.info.message(EPrefixInternalError, "Cannot fold constant", this->getLine()); + return 0; + } + } + } else { + // + // Do unary operations + // + TIntermConstantUnion *newNode = 0; + constUnion* tempConstArray = new constUnion[this->getSize()]; + if (this->getSize() > 1) { + for (int i = 0; i < this->getSize(); i++) { + switch(op) { + case EOpNegative: + switch (this->getType().getBasicType()) { + case EbtFloat: tempConstArray[i].fConst = -(unionArray[i].fConst); break; + case EbtInt: tempConstArray[i].iConst = -(unionArray[i].iConst); break; + default: + infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant", this->getLine()); + return 0; + } + break; + case EOpLogicalNot: // this code is written for possible future use, will not get executed currently + switch (this->getType().getBasicType()) { + case EbtBool: tempConstArray[i].bConst = !(unionArray[i].bConst); break; + default: + infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant", this->getLine()); + return 0; + } + break; + default: + return 0; + } + } + newNode = new TIntermConstantUnion(tempConstArray, this->getType()); + newNode->setLine(this->getLine()); + return newNode; + } else { + switch(op) { + //?? add constant intrinsics + case EOpNegative: + switch (this->getType().getBasicType()) { + case EbtInt: + tempConstArray->iConst = -(this->getUnionArrayPointer()->iConst); + newNode = new TIntermConstantUnion(tempConstArray, TType(EbtInt, EvqConst)); + break; + case EbtFloat: + tempConstArray->fConst = -(this->getUnionArrayPointer()->fConst); + newNode = new TIntermConstantUnion(tempConstArray, TType(EbtFloat, EvqConst)); + break; + default: + infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant", line); + return 0; + } + break; + case EOpLogicalNot: + switch (this->getType().getBasicType()) { + case EbtBool: + tempConstArray->bConst = !this->getUnionArrayPointer()->bConst; + newNode = new TIntermConstantUnion(tempConstArray, TType(EbtBool, EvqConst)); + break; + default: + infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant", line); + return 0; + } + break; + default: + return 0; + } + newNode->setLine(this->getLine()); + return newNode; + + } + } + + return this; +} + +TIntermConstantUnion* TIntermediate::changeAggrToTempConst(TIntermAggregate* node, TSymbolTable& symbolTable, TSourceLoc line) +{ + constUnion* unionArray = new constUnion[node->getType().getInstanceSize()]; + bool returnVal; + + if (node->getSequence().size() == 1 && node->getSequence()[0]->getAsTyped()->getAsConstantUnion()) { + returnVal = parseConstTree(line, node, unionArray, node->getOp(), symbolTable, node->getType(), true); + } + else { + returnVal = parseConstTree(line, node, unionArray, node->getOp(), symbolTable, node->getType()); + } + + if (returnVal) + unionArray = 0; + + return (addConstantUnion(unionArray, node->getType(), node->getLine())); +} + +TIntermTyped* TIntermediate::copyConstUnion(TIntermConstantUnion* node) +{ + constUnion *unionArray = node->getUnionArrayPointer(); + + if (!unionArray) + return 0; + + int size; + if (node->getType().getBasicType() == EbtStruct) + //?? We should actually be calling getStructSize() function and not setStructSize. This problem occurs in case + // of nested/embedded structs. + size = node->getType().setStructSize(node->getType().getStruct()); + //size = node->getType().getStructSize(); + else + size = node->getType().getInstanceSize(); + + constUnion *newSpace = new constUnion[size]; + + for (int i = 0; i < size; i++) + newSpace[i] = unionArray[i]; + + node->setUnionArrayPointer(newSpace); + return node; +} + +TIntermTyped* TIntermediate::promoteConstantUnion(TBasicType promoteTo, TIntermConstantUnion* node) +{ + constUnion *rightUnionArray = node->getUnionArrayPointer(); + int size = node->getType().getInstanceSize(); + + constUnion *leftUnionArray = new constUnion[size]; + + for (int i=0; i < size; i++) { + + switch (promoteTo) { + case EbtFloat: + switch (node->getType().getBasicType()) { + case EbtInt: + (leftUnionArray[i]).fConst = static_cast(rightUnionArray[i].iConst); + break; + case EbtBool: + (leftUnionArray[i]).fConst = static_cast(rightUnionArray[i].bConst); + break; + case EbtFloat: + (leftUnionArray[i]).fConst = rightUnionArray[i].fConst; + break; + default: + infoSink.info.message(EPrefixInternalError, "Cannot promote", node->getLine()); + return 0; + } + break; + case EbtInt: + switch (node->getType().getBasicType()) { + case EbtInt: + (leftUnionArray[i]).iConst = rightUnionArray[i].iConst; + break; + case EbtBool: + (leftUnionArray[i]).iConst = static_cast(rightUnionArray[i].bConst); + break; + case EbtFloat: + (leftUnionArray[i]).iConst = static_cast(rightUnionArray[i].fConst); + break; + default: + infoSink.info.message(EPrefixInternalError, "Cannot promote", node->getLine()); + return 0; + } + break; + case EbtBool: + switch (node->getType().getBasicType()) { + case EbtInt: + (leftUnionArray[i]).bConst = rightUnionArray[i].iConst != 0; + break; + case EbtBool: + (leftUnionArray[i]).bConst = rightUnionArray[i].bConst; + break; + case EbtFloat: + (leftUnionArray[i]).bConst = rightUnionArray[i].fConst != 0.0; + break; + default: + infoSink.info.message(EPrefixInternalError, "Cannot promote", node->getLine()); + return 0; + } + + break; + default: + infoSink.info.message(EPrefixInternalError, "Incorrect data type found", node->getLine()); + return 0; + } + + } + + const TType& t = node->getType(); + + return addConstantUnion(leftUnionArray, TType(promoteTo, t.getQualifier(), t.getNominalSize(), t.isMatrix(), t.isArray()), node->getLine()); +} + +// +// This method inserts the child nodes into the parent node at the given location specified +// by parentNodeIter. offset tells the integer offset into the parent vector that points to +// the child node. sequenceVector is the parent vector. +// Returns reference to the last inserted child node +// increments the offset based on the number of child nodes added +// +void TIntermediate::removeChildNode(TIntermSequence &parentSequence, TType& parentType, int& offset, TIntermSequence::iterator& parentNodeIter, TIntermAggregate* child) +{ + if (!child) + return; + + parentNodeIter = parentSequence.begin() + offset; + + TIntermSequence& childSequence = child->getSequence(); + int oldSize = static_cast(parentSequence.size()); + if (childSequence.size() == 1) { + if (!removeMatrixConstNode(parentSequence, parentType, child, offset)) { + for (int i = 0; i < child->getType().getInstanceSize(); i++) { + constUnion* constantUnion = new constUnion[1]; + *constantUnion = *(childSequence[0]->getAsConstantUnion()->getUnionArrayPointer()); + TIntermConstantUnion *constant = new TIntermConstantUnion(constantUnion, + childSequence[0]->getAsConstantUnion()->getType()); + constant->setLine(child->getLine()); + parentNodeIter = parentSequence.begin() + offset; + parentSequence.insert(parentNodeIter, constant); + } + } + } else + parentSequence.insert(parentNodeIter, childSequence.begin(), childSequence.end()); + + int newSize = static_cast(parentSequence.size()); + offset = offset + newSize - oldSize; + parentNodeIter = parentSequence.begin() + offset; + parentNodeIter = parentSequence.erase(parentNodeIter); + offset--; + parentNodeIter--; +} + +// +// The parent has only one child node. This method is not implemented +// for parent that is a structure +// +TIntermTyped* TIntermediate::removeChildNode(TIntermTyped* parent, TType* parentType, TIntermAggregate* child) +{ + TIntermTyped* resultNode = 0; + + if (parentType->getInstanceSize() == 1) { + resultNode = child->getSequence()[0]->getAsTyped(); + } else { + int size = parentType->getInstanceSize(); + TIntermSequence& parentSequence = parent->getAsAggregate()->getSequence(); + TIntermSequence& childSequence = child->getSequence(); + + if (childSequence.size() == 1) { + if (!removeMatrixConstNode(parentSequence, *parentType, child, 1)) + parentSequence.push_back(child->getSequence()[0]); + } else { + for (int i = 0; i < size; i++) { + parentSequence.push_back(child->getSequence()[i]); + } + } + parentSequence.erase(parentSequence.begin()); + + return parent; + } + + return resultNode; +} + +bool TIntermediate::removeMatrixConstNode(TIntermSequence &parentSequence, TType& parentType, TIntermAggregate* child, int offset) +{ + if (!child) + return false; + + TIntermSequence::iterator parentNodeIter; + TIntermSequence &childSequence = child->getSequence(); + + switch (child->getOp()) { + case EOpConstructMat2: + case EOpConstructMat3: + case EOpConstructMat4: + {// support MSVC++6.0 + for (int i = 0; i < child->getType().getInstanceSize(); i++) { + constUnion* constantUnion = new constUnion[1]; + if (i % (child->getType().getNominalSize() + 1) == 0) { + *constantUnion = *(childSequence[0]->getAsConstantUnion()->getUnionArrayPointer()); + } else { + switch (parentType.getBasicType()) { + case EbtInt: constantUnion->iConst = 0; break; + case EbtFloat: constantUnion->fConst = 0.0; break; + case EbtBool: constantUnion->bConst = false; break; + default: ; /* default added by BrianP */ + } + } + TIntermConstantUnion *constant = new TIntermConstantUnion(constantUnion, + childSequence[0]->getAsConstantUnion()->getType()); + constant->setLine(child->getLine()); + parentNodeIter = parentSequence.begin() + offset + i; + parentSequence.insert(parentNodeIter, constant); + } + } + return true; + default: + return false; + } +} + +void TIntermAggregate::addToPragmaTable(const TPragmaTable& pTable) +{ + assert (!pragmaTable); + pragmaTable = new TPragmaTable(); + *pragmaTable = pTable; +} + -- cgit v1.2.3