michael@0: // michael@0: // Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved. michael@0: // Use of this source code is governed by a BSD-style license that can be michael@0: // found in the LICENSE file. michael@0: // michael@0: michael@0: // michael@0: // Build the intermediate representation. michael@0: // michael@0: michael@0: #include michael@0: #include michael@0: #include michael@0: michael@0: #include "compiler/HashNames.h" michael@0: #include "compiler/localintermediate.h" michael@0: #include "compiler/QualifierAlive.h" michael@0: #include "compiler/RemoveTree.h" michael@0: michael@0: bool CompareStructure(const TType& leftNodeType, ConstantUnion* rightUnionArray, ConstantUnion* leftUnionArray); michael@0: michael@0: static TPrecision GetHigherPrecision( TPrecision left, TPrecision right ){ michael@0: return left > right ? left : right; michael@0: } michael@0: michael@0: const char* getOperatorString(TOperator op) { michael@0: switch (op) { michael@0: case EOpInitialize: return "="; michael@0: case EOpAssign: return "="; michael@0: case EOpAddAssign: return "+="; michael@0: case EOpSubAssign: return "-="; michael@0: case EOpDivAssign: return "/="; michael@0: michael@0: // Fall-through. michael@0: case EOpMulAssign: michael@0: case EOpVectorTimesMatrixAssign: michael@0: case EOpVectorTimesScalarAssign: michael@0: case EOpMatrixTimesScalarAssign: michael@0: case EOpMatrixTimesMatrixAssign: return "*="; michael@0: michael@0: // Fall-through. michael@0: case EOpIndexDirect: michael@0: case EOpIndexIndirect: return "[]"; michael@0: michael@0: case EOpIndexDirectStruct: return "."; michael@0: case EOpVectorSwizzle: return "."; michael@0: case EOpAdd: return "+"; michael@0: case EOpSub: return "-"; michael@0: case EOpMul: return "*"; michael@0: case EOpDiv: return "/"; michael@0: case EOpMod: UNIMPLEMENTED(); break; michael@0: case EOpEqual: return "=="; michael@0: case EOpNotEqual: return "!="; michael@0: case EOpLessThan: return "<"; michael@0: case EOpGreaterThan: return ">"; michael@0: case EOpLessThanEqual: return "<="; michael@0: case EOpGreaterThanEqual: return ">="; michael@0: michael@0: // Fall-through. michael@0: case EOpVectorTimesScalar: michael@0: case EOpVectorTimesMatrix: michael@0: case EOpMatrixTimesVector: michael@0: case EOpMatrixTimesScalar: michael@0: case EOpMatrixTimesMatrix: return "*"; michael@0: michael@0: case EOpLogicalOr: return "||"; michael@0: case EOpLogicalXor: return "^^"; michael@0: case EOpLogicalAnd: return "&&"; michael@0: case EOpNegative: return "-"; michael@0: case EOpVectorLogicalNot: return "not"; michael@0: case EOpLogicalNot: return "!"; michael@0: case EOpPostIncrement: return "++"; michael@0: case EOpPostDecrement: return "--"; michael@0: case EOpPreIncrement: return "++"; michael@0: case EOpPreDecrement: return "--"; michael@0: michael@0: // Fall-through. michael@0: case EOpConvIntToBool: michael@0: case EOpConvFloatToBool: return "bool"; michael@0: michael@0: // Fall-through. michael@0: case EOpConvBoolToFloat: michael@0: case EOpConvIntToFloat: return "float"; michael@0: michael@0: // Fall-through. michael@0: case EOpConvFloatToInt: michael@0: case EOpConvBoolToInt: return "int"; michael@0: michael@0: case EOpRadians: return "radians"; michael@0: case EOpDegrees: return "degrees"; michael@0: case EOpSin: return "sin"; michael@0: case EOpCos: return "cos"; michael@0: case EOpTan: return "tan"; michael@0: case EOpAsin: return "asin"; michael@0: case EOpAcos: return "acos"; michael@0: case EOpAtan: return "atan"; michael@0: case EOpExp: return "exp"; michael@0: case EOpLog: return "log"; michael@0: case EOpExp2: return "exp2"; michael@0: case EOpLog2: return "log2"; michael@0: case EOpSqrt: return "sqrt"; michael@0: case EOpInverseSqrt: return "inversesqrt"; michael@0: case EOpAbs: return "abs"; michael@0: case EOpSign: return "sign"; michael@0: case EOpFloor: return "floor"; michael@0: case EOpCeil: return "ceil"; michael@0: case EOpFract: return "fract"; michael@0: case EOpLength: return "length"; michael@0: case EOpNormalize: return "normalize"; michael@0: case EOpDFdx: return "dFdx"; michael@0: case EOpDFdy: return "dFdy"; michael@0: case EOpFwidth: return "fwidth"; michael@0: case EOpAny: return "any"; michael@0: case EOpAll: return "all"; michael@0: michael@0: default: break; michael@0: } michael@0: return ""; michael@0: } michael@0: michael@0: //////////////////////////////////////////////////////////////////////////// michael@0: // michael@0: // First set of functions are to help build the intermediate representation. michael@0: // These functions are not member functions of the nodes. michael@0: // They are called from parser productions. michael@0: // michael@0: ///////////////////////////////////////////////////////////////////////////// michael@0: michael@0: // michael@0: // Add a terminal node for an identifier in an expression. michael@0: // michael@0: // Returns the added node. michael@0: // michael@0: TIntermSymbol* TIntermediate::addSymbol(int id, const TString& name, const TType& type, const TSourceLoc& line) michael@0: { michael@0: TIntermSymbol* node = new TIntermSymbol(id, name, type); michael@0: node->setLine(line); michael@0: michael@0: return node; michael@0: } michael@0: michael@0: // michael@0: // Connect two nodes with a new parent that does a binary operation on the nodes. michael@0: // michael@0: // Returns the added node. michael@0: // michael@0: TIntermTyped* TIntermediate::addBinaryMath(TOperator op, TIntermTyped* left, TIntermTyped* right, const TSourceLoc& line, TSymbolTable& symbolTable) michael@0: { michael@0: switch (op) { michael@0: case EOpEqual: michael@0: case EOpNotEqual: michael@0: if (left->isArray()) michael@0: return 0; michael@0: break; michael@0: case EOpLessThan: michael@0: case EOpGreaterThan: michael@0: case EOpLessThanEqual: michael@0: case EOpGreaterThanEqual: michael@0: if (left->isMatrix() || left->isArray() || left->isVector() || left->getBasicType() == EbtStruct) { michael@0: return 0; michael@0: } michael@0: break; michael@0: case EOpLogicalOr: michael@0: case EOpLogicalXor: michael@0: case EOpLogicalAnd: michael@0: if (left->getBasicType() != EbtBool || left->isMatrix() || left->isArray() || left->isVector()) { michael@0: return 0; michael@0: } michael@0: break; michael@0: case EOpAdd: michael@0: case EOpSub: michael@0: case EOpDiv: michael@0: case EOpMul: michael@0: if (left->getBasicType() == EbtStruct || left->getBasicType() == EbtBool) michael@0: return 0; michael@0: default: break; michael@0: } michael@0: michael@0: // michael@0: // First try converting the children to compatible types. michael@0: // michael@0: if (left->getType().getStruct() && right->getType().getStruct()) { michael@0: if (left->getType() != right->getType()) michael@0: return 0; michael@0: } else { michael@0: TIntermTyped* child = addConversion(op, left->getType(), right); michael@0: if (child) michael@0: right = child; michael@0: else { michael@0: child = addConversion(op, right->getType(), left); michael@0: if (child) michael@0: left = child; michael@0: else michael@0: return 0; michael@0: } michael@0: } michael@0: michael@0: // michael@0: // Need a new node holding things together then. Make michael@0: // one and promote it to the right type. michael@0: // michael@0: TIntermBinary* node = new TIntermBinary(op); michael@0: node->setLine(line); michael@0: michael@0: node->setLeft(left); michael@0: node->setRight(right); michael@0: if (!node->promote(infoSink)) michael@0: return 0; michael@0: michael@0: // michael@0: // See if we can fold constants. michael@0: // michael@0: TIntermTyped* typedReturnNode = 0; michael@0: TIntermConstantUnion *leftTempConstant = left->getAsConstantUnion(); michael@0: TIntermConstantUnion *rightTempConstant = right->getAsConstantUnion(); michael@0: if (leftTempConstant && rightTempConstant) { michael@0: typedReturnNode = leftTempConstant->fold(node->getOp(), rightTempConstant, infoSink); michael@0: michael@0: if (typedReturnNode) michael@0: return typedReturnNode; michael@0: } michael@0: michael@0: return node; michael@0: } michael@0: michael@0: // michael@0: // Connect two nodes through an assignment. michael@0: // michael@0: // Returns the added node. michael@0: // michael@0: TIntermTyped* TIntermediate::addAssign(TOperator op, TIntermTyped* left, TIntermTyped* right, const TSourceLoc& line) michael@0: { michael@0: // michael@0: // Like adding binary math, except the conversion can only go michael@0: // from right to left. michael@0: // michael@0: TIntermBinary* node = new TIntermBinary(op); michael@0: node->setLine(line); michael@0: michael@0: TIntermTyped* child = addConversion(op, left->getType(), right); michael@0: if (child == 0) michael@0: return 0; michael@0: michael@0: node->setLeft(left); michael@0: node->setRight(child); michael@0: if (! node->promote(infoSink)) michael@0: return 0; michael@0: michael@0: return node; michael@0: } michael@0: michael@0: // michael@0: // Connect two nodes through an index operator, where the left node is the base michael@0: // of an array or struct, and the right node is a direct or indirect offset. michael@0: // michael@0: // Returns the added node. michael@0: // The caller should set the type of the returned node. michael@0: // michael@0: TIntermTyped* TIntermediate::addIndex(TOperator op, TIntermTyped* base, TIntermTyped* index, const TSourceLoc& line) michael@0: { michael@0: TIntermBinary* node = new TIntermBinary(op); michael@0: node->setLine(line); michael@0: node->setLeft(base); michael@0: node->setRight(index); michael@0: michael@0: // caller should set the type michael@0: michael@0: return node; michael@0: } michael@0: michael@0: // michael@0: // Add one node as the parent of another that it operates on. michael@0: // michael@0: // Returns the added node. michael@0: // michael@0: TIntermTyped* TIntermediate::addUnaryMath(TOperator op, TIntermNode* childNode, const TSourceLoc& line, TSymbolTable& symbolTable) michael@0: { michael@0: TIntermUnary* node; michael@0: TIntermTyped* child = childNode->getAsTyped(); michael@0: michael@0: if (child == 0) { michael@0: infoSink.info.message(EPrefixInternalError, line, "Bad type in AddUnaryMath"); michael@0: return 0; michael@0: } michael@0: michael@0: switch (op) { michael@0: case EOpLogicalNot: michael@0: if (child->getType().getBasicType() != EbtBool || child->getType().isMatrix() || child->getType().isArray() || child->getType().isVector()) { michael@0: return 0; michael@0: } michael@0: break; michael@0: michael@0: case EOpPostIncrement: michael@0: case EOpPreIncrement: michael@0: case EOpPostDecrement: michael@0: case EOpPreDecrement: michael@0: case EOpNegative: michael@0: if (child->getType().getBasicType() == EbtStruct || child->getType().isArray()) michael@0: return 0; michael@0: default: break; michael@0: } michael@0: michael@0: // michael@0: // Do we need to promote the operand? michael@0: // michael@0: // Note: Implicit promotions were removed from the language. michael@0: // michael@0: TBasicType newType = EbtVoid; michael@0: switch (op) { michael@0: case EOpConstructInt: newType = EbtInt; break; michael@0: case EOpConstructBool: newType = EbtBool; break; michael@0: case EOpConstructFloat: newType = EbtFloat; break; michael@0: default: break; michael@0: } michael@0: michael@0: if (newType != EbtVoid) { michael@0: child = addConversion(op, TType(newType, child->getPrecision(), EvqTemporary, michael@0: child->getNominalSize(), michael@0: child->isMatrix(), michael@0: child->isArray()), michael@0: child); michael@0: if (child == 0) michael@0: return 0; michael@0: } michael@0: michael@0: // michael@0: // For constructors, we are now done, it's all in the conversion. michael@0: // michael@0: switch (op) { michael@0: case EOpConstructInt: michael@0: case EOpConstructBool: michael@0: case EOpConstructFloat: michael@0: return child; michael@0: default: break; michael@0: } michael@0: michael@0: TIntermConstantUnion *childTempConstant = 0; michael@0: if (child->getAsConstantUnion()) michael@0: childTempConstant = child->getAsConstantUnion(); michael@0: michael@0: // michael@0: // Make a new node for the operator. michael@0: // michael@0: node = new TIntermUnary(op); michael@0: node->setLine(line); michael@0: node->setOperand(child); michael@0: michael@0: if (! node->promote(infoSink)) michael@0: return 0; michael@0: michael@0: if (childTempConstant) { michael@0: TIntermTyped* newChild = childTempConstant->fold(op, 0, infoSink); michael@0: michael@0: if (newChild) michael@0: return newChild; michael@0: } michael@0: michael@0: return node; michael@0: } michael@0: michael@0: // michael@0: // This is the safe way to change the operator on an aggregate, as it michael@0: // does lots of error checking and fixing. Especially for establishing michael@0: // a function call's operation on it's set of parameters. Sequences michael@0: // of instructions are also aggregates, but they just direnctly set michael@0: // their operator to EOpSequence. michael@0: // michael@0: // Returns an aggregate node, which could be the one passed in if michael@0: // it was already an aggregate but no operator was set. michael@0: // michael@0: TIntermAggregate* TIntermediate::setAggregateOperator(TIntermNode* node, TOperator op, const TSourceLoc& line) michael@0: { michael@0: TIntermAggregate* aggNode; michael@0: michael@0: // michael@0: // Make sure we have an aggregate. If not turn it into one. michael@0: // michael@0: if (node) { michael@0: aggNode = node->getAsAggregate(); michael@0: if (aggNode == 0 || aggNode->getOp() != EOpNull) { michael@0: // michael@0: // Make an aggregate containing this node. michael@0: // michael@0: aggNode = new TIntermAggregate(); michael@0: aggNode->getSequence().push_back(node); michael@0: } michael@0: } else michael@0: aggNode = new TIntermAggregate(); michael@0: michael@0: // michael@0: // Set the operator. michael@0: // michael@0: aggNode->setOp(op); michael@0: aggNode->setLine(line); michael@0: michael@0: return aggNode; michael@0: } michael@0: michael@0: // michael@0: // Convert one type to another. michael@0: // michael@0: // Returns the node representing the conversion, which could be the same michael@0: // node passed in if no conversion was needed. michael@0: // michael@0: // Return 0 if a conversion can't be done. michael@0: // michael@0: TIntermTyped* TIntermediate::addConversion(TOperator op, const TType& type, TIntermTyped* node) michael@0: { michael@0: // michael@0: // Does the base type allow operation? michael@0: // michael@0: switch (node->getBasicType()) { michael@0: case EbtVoid: michael@0: case EbtSampler2D: michael@0: case EbtSamplerCube: michael@0: return 0; michael@0: default: break; michael@0: } michael@0: michael@0: // michael@0: // Otherwise, if types are identical, no problem michael@0: // michael@0: if (type == node->getType()) michael@0: return node; michael@0: michael@0: // michael@0: // If one's a structure, then no conversions. michael@0: // michael@0: if (type.getStruct() || node->getType().getStruct()) michael@0: return 0; michael@0: michael@0: // michael@0: // If one's an array, then no conversions. michael@0: // michael@0: if (type.isArray() || node->getType().isArray()) michael@0: return 0; michael@0: michael@0: TBasicType promoteTo; michael@0: michael@0: switch (op) { michael@0: // michael@0: // Explicit conversions michael@0: // michael@0: case EOpConstructBool: michael@0: promoteTo = EbtBool; michael@0: break; michael@0: case EOpConstructFloat: michael@0: promoteTo = EbtFloat; michael@0: break; michael@0: case EOpConstructInt: michael@0: promoteTo = EbtInt; michael@0: break; michael@0: default: michael@0: // michael@0: // implicit conversions were removed from the language. michael@0: // michael@0: if (type.getBasicType() != node->getType().getBasicType()) michael@0: return 0; michael@0: // michael@0: // Size and structure could still differ, but that's michael@0: // handled by operator promotion. michael@0: // michael@0: return node; michael@0: } michael@0: michael@0: if (node->getAsConstantUnion()) { michael@0: michael@0: return (promoteConstantUnion(promoteTo, node->getAsConstantUnion())); michael@0: } else { michael@0: michael@0: // michael@0: // Add a new newNode for the conversion. michael@0: // michael@0: TIntermUnary* newNode = 0; michael@0: michael@0: TOperator newOp = EOpNull; michael@0: switch (promoteTo) { michael@0: case EbtFloat: michael@0: switch (node->getBasicType()) { michael@0: case EbtInt: newOp = EOpConvIntToFloat; break; michael@0: case EbtBool: newOp = EOpConvBoolToFloat; break; michael@0: default: michael@0: infoSink.info.message(EPrefixInternalError, node->getLine(), "Bad promotion node"); michael@0: return 0; michael@0: } michael@0: break; michael@0: case EbtBool: michael@0: switch (node->getBasicType()) { michael@0: case EbtInt: newOp = EOpConvIntToBool; break; michael@0: case EbtFloat: newOp = EOpConvFloatToBool; break; michael@0: default: michael@0: infoSink.info.message(EPrefixInternalError, node->getLine(), "Bad promotion node"); michael@0: return 0; michael@0: } michael@0: break; michael@0: case EbtInt: michael@0: switch (node->getBasicType()) { michael@0: case EbtBool: newOp = EOpConvBoolToInt; break; michael@0: case EbtFloat: newOp = EOpConvFloatToInt; break; michael@0: default: michael@0: infoSink.info.message(EPrefixInternalError, node->getLine(), "Bad promotion node"); michael@0: return 0; michael@0: } michael@0: break; michael@0: default: michael@0: infoSink.info.message(EPrefixInternalError, node->getLine(), "Bad promotion type"); michael@0: return 0; michael@0: } michael@0: michael@0: TType type(promoteTo, node->getPrecision(), EvqTemporary, node->getNominalSize(), node->isMatrix(), node->isArray()); michael@0: newNode = new TIntermUnary(newOp, type); michael@0: newNode->setLine(node->getLine()); michael@0: newNode->setOperand(node); michael@0: michael@0: return newNode; michael@0: } michael@0: } michael@0: michael@0: // michael@0: // Safe way to combine two nodes into an aggregate. Works with null pointers, michael@0: // a node that's not a aggregate yet, etc. michael@0: // michael@0: // Returns the resulting aggregate, unless 0 was passed in for michael@0: // both existing nodes. michael@0: // michael@0: TIntermAggregate* TIntermediate::growAggregate(TIntermNode* left, TIntermNode* right, const TSourceLoc& line) michael@0: { michael@0: if (left == 0 && right == 0) michael@0: return 0; michael@0: michael@0: TIntermAggregate* aggNode = 0; michael@0: if (left) michael@0: aggNode = left->getAsAggregate(); michael@0: if (!aggNode || aggNode->getOp() != EOpNull) { michael@0: aggNode = new TIntermAggregate; michael@0: if (left) michael@0: aggNode->getSequence().push_back(left); michael@0: } michael@0: michael@0: if (right) michael@0: aggNode->getSequence().push_back(right); michael@0: michael@0: aggNode->setLine(line); michael@0: michael@0: return aggNode; michael@0: } michael@0: michael@0: // michael@0: // Turn an existing node into an aggregate. michael@0: // michael@0: // Returns an aggregate, unless 0 was passed in for the existing node. michael@0: // michael@0: TIntermAggregate* TIntermediate::makeAggregate(TIntermNode* node, const TSourceLoc& line) michael@0: { michael@0: if (node == 0) michael@0: return 0; michael@0: michael@0: TIntermAggregate* aggNode = new TIntermAggregate; michael@0: aggNode->getSequence().push_back(node); michael@0: aggNode->setLine(line); michael@0: michael@0: return aggNode; michael@0: } michael@0: michael@0: // michael@0: // For "if" test nodes. There are three children; a condition, michael@0: // a true path, and a false path. The two paths are in the michael@0: // nodePair. michael@0: // michael@0: // Returns the selection node created. michael@0: // michael@0: TIntermNode* TIntermediate::addSelection(TIntermTyped* cond, TIntermNodePair nodePair, const TSourceLoc& line) michael@0: { michael@0: // michael@0: // For compile time constant selections, prune the code and michael@0: // test now. michael@0: // michael@0: michael@0: if (cond->getAsTyped() && cond->getAsTyped()->getAsConstantUnion()) { michael@0: if (cond->getAsConstantUnion()->getBConst(0) == true) michael@0: return nodePair.node1 ? setAggregateOperator(nodePair.node1, EOpSequence, nodePair.node1->getLine()) : NULL; michael@0: else michael@0: return nodePair.node2 ? setAggregateOperator(nodePair.node2, EOpSequence, nodePair.node2->getLine()) : NULL; michael@0: } michael@0: michael@0: TIntermSelection* node = new TIntermSelection(cond, nodePair.node1, nodePair.node2); michael@0: node->setLine(line); michael@0: michael@0: return node; michael@0: } michael@0: michael@0: michael@0: TIntermTyped* TIntermediate::addComma(TIntermTyped* left, TIntermTyped* right, const TSourceLoc& line) michael@0: { michael@0: if (left->getType().getQualifier() == EvqConst && right->getType().getQualifier() == EvqConst) { michael@0: return right; michael@0: } else { michael@0: TIntermTyped *commaAggregate = growAggregate(left, right, line); michael@0: commaAggregate->getAsAggregate()->setOp(EOpComma); michael@0: commaAggregate->setType(right->getType()); michael@0: commaAggregate->getTypePointer()->setQualifier(EvqTemporary); michael@0: return commaAggregate; michael@0: } michael@0: } michael@0: michael@0: // michael@0: // For "?:" test nodes. There are three children; a condition, michael@0: // a true path, and a false path. The two paths are specified michael@0: // as separate parameters. michael@0: // michael@0: // Returns the selection node created, or 0 if one could not be. michael@0: // michael@0: TIntermTyped* TIntermediate::addSelection(TIntermTyped* cond, TIntermTyped* trueBlock, TIntermTyped* falseBlock, const TSourceLoc& line) michael@0: { michael@0: // michael@0: // Get compatible types. michael@0: // michael@0: TIntermTyped* child = addConversion(EOpSequence, trueBlock->getType(), falseBlock); michael@0: if (child) michael@0: falseBlock = child; michael@0: else { michael@0: child = addConversion(EOpSequence, falseBlock->getType(), trueBlock); michael@0: if (child) michael@0: trueBlock = child; michael@0: else michael@0: return 0; michael@0: } michael@0: michael@0: // michael@0: // See if all the operands are constant, then fold it otherwise not. michael@0: // michael@0: michael@0: if (cond->getAsConstantUnion() && trueBlock->getAsConstantUnion() && falseBlock->getAsConstantUnion()) { michael@0: if (cond->getAsConstantUnion()->getBConst(0)) michael@0: return trueBlock; michael@0: else michael@0: return falseBlock; michael@0: } michael@0: michael@0: // michael@0: // Make a selection node. michael@0: // michael@0: TIntermSelection* node = new TIntermSelection(cond, trueBlock, falseBlock, trueBlock->getType()); michael@0: node->getTypePointer()->setQualifier(EvqTemporary); michael@0: node->setLine(line); michael@0: michael@0: return node; michael@0: } michael@0: michael@0: // michael@0: // Constant terminal nodes. Has a union that contains bool, float or int constants michael@0: // michael@0: // Returns the constant union node created. michael@0: // michael@0: michael@0: TIntermConstantUnion* TIntermediate::addConstantUnion(ConstantUnion* unionArrayPointer, const TType& t, const TSourceLoc& line) michael@0: { michael@0: TIntermConstantUnion* node = new TIntermConstantUnion(unionArrayPointer, t); michael@0: node->setLine(line); michael@0: michael@0: return node; michael@0: } michael@0: michael@0: TIntermTyped* TIntermediate::addSwizzle(TVectorFields& fields, const TSourceLoc& line) michael@0: { michael@0: michael@0: TIntermAggregate* node = new TIntermAggregate(EOpSequence); michael@0: michael@0: node->setLine(line); michael@0: TIntermConstantUnion* constIntNode; michael@0: TIntermSequence &sequenceVector = node->getSequence(); michael@0: ConstantUnion* unionArray; michael@0: michael@0: for (int i = 0; i < fields.num; i++) { michael@0: unionArray = new ConstantUnion[1]; michael@0: unionArray->setIConst(fields.offsets[i]); michael@0: constIntNode = addConstantUnion(unionArray, TType(EbtInt, EbpUndefined, EvqConst), line); michael@0: sequenceVector.push_back(constIntNode); michael@0: } michael@0: michael@0: return node; michael@0: } michael@0: michael@0: // michael@0: // Create loop nodes. michael@0: // michael@0: TIntermNode* TIntermediate::addLoop(TLoopType type, TIntermNode* init, TIntermTyped* cond, TIntermTyped* expr, TIntermNode* body, const TSourceLoc& line) michael@0: { michael@0: TIntermNode* node = new TIntermLoop(type, init, cond, expr, body); michael@0: node->setLine(line); michael@0: michael@0: return node; michael@0: } michael@0: michael@0: // michael@0: // Add branches. michael@0: // michael@0: TIntermBranch* TIntermediate::addBranch(TOperator branchOp, const TSourceLoc& line) michael@0: { michael@0: return addBranch(branchOp, 0, line); michael@0: } michael@0: michael@0: TIntermBranch* TIntermediate::addBranch(TOperator branchOp, TIntermTyped* expression, const TSourceLoc& line) michael@0: { michael@0: TIntermBranch* node = new TIntermBranch(branchOp, expression); michael@0: node->setLine(line); michael@0: michael@0: return node; michael@0: } michael@0: michael@0: // michael@0: // This is to be executed once the final root is put on top by the parsing michael@0: // process. michael@0: // michael@0: bool TIntermediate::postProcess(TIntermNode* root) michael@0: { michael@0: if (root == 0) michael@0: return true; michael@0: michael@0: // michael@0: // First, finish off the top level sequence, if any michael@0: // michael@0: TIntermAggregate* aggRoot = root->getAsAggregate(); michael@0: if (aggRoot && aggRoot->getOp() == EOpNull) michael@0: aggRoot->setOp(EOpSequence); michael@0: michael@0: return true; michael@0: } michael@0: michael@0: // michael@0: // This deletes the tree. michael@0: // michael@0: void TIntermediate::remove(TIntermNode* root) michael@0: { michael@0: if (root) michael@0: RemoveAllTreeNodes(root); michael@0: } michael@0: michael@0: //////////////////////////////////////////////////////////////// michael@0: // michael@0: // Member functions of the nodes used for building the tree. michael@0: // michael@0: //////////////////////////////////////////////////////////////// michael@0: michael@0: // michael@0: // Say whether or not an operation node changes the value of a variable. michael@0: // michael@0: // Returns true if state is modified. michael@0: // michael@0: bool TIntermOperator::modifiesState() const michael@0: { michael@0: switch (op) { michael@0: case EOpPostIncrement: michael@0: case EOpPostDecrement: michael@0: case EOpPreIncrement: michael@0: case EOpPreDecrement: michael@0: case EOpAssign: michael@0: case EOpAddAssign: michael@0: case EOpSubAssign: michael@0: case EOpMulAssign: michael@0: case EOpVectorTimesMatrixAssign: michael@0: case EOpVectorTimesScalarAssign: michael@0: case EOpMatrixTimesScalarAssign: michael@0: case EOpMatrixTimesMatrixAssign: michael@0: case EOpDivAssign: michael@0: return true; michael@0: default: michael@0: return false; michael@0: } michael@0: } michael@0: michael@0: // michael@0: // returns true if the operator is for one of the constructors michael@0: // michael@0: bool TIntermOperator::isConstructor() const michael@0: { michael@0: switch (op) { michael@0: case EOpConstructVec2: michael@0: case EOpConstructVec3: michael@0: case EOpConstructVec4: michael@0: case EOpConstructMat2: michael@0: case EOpConstructMat3: michael@0: case EOpConstructMat4: michael@0: case EOpConstructFloat: michael@0: case EOpConstructIVec2: michael@0: case EOpConstructIVec3: michael@0: case EOpConstructIVec4: michael@0: case EOpConstructInt: michael@0: case EOpConstructBVec2: michael@0: case EOpConstructBVec3: michael@0: case EOpConstructBVec4: michael@0: case EOpConstructBool: michael@0: case EOpConstructStruct: michael@0: return true; michael@0: default: michael@0: return false; michael@0: } michael@0: } michael@0: // michael@0: // Make sure the type of a unary operator is appropriate for its michael@0: // combination of operation and operand type. michael@0: // michael@0: // Returns false in nothing makes sense. michael@0: // michael@0: bool TIntermUnary::promote(TInfoSink&) michael@0: { michael@0: switch (op) { michael@0: case EOpLogicalNot: michael@0: if (operand->getBasicType() != EbtBool) michael@0: return false; michael@0: break; michael@0: case EOpNegative: michael@0: case EOpPostIncrement: michael@0: case EOpPostDecrement: michael@0: case EOpPreIncrement: michael@0: case EOpPreDecrement: michael@0: if (operand->getBasicType() == EbtBool) michael@0: return false; michael@0: break; michael@0: michael@0: // operators for built-ins are already type checked against their prototype michael@0: case EOpAny: michael@0: case EOpAll: michael@0: case EOpVectorLogicalNot: michael@0: return true; michael@0: michael@0: default: michael@0: if (operand->getBasicType() != EbtFloat) michael@0: return false; michael@0: } michael@0: michael@0: setType(operand->getType()); michael@0: type.setQualifier(EvqTemporary); michael@0: michael@0: return true; michael@0: } michael@0: michael@0: // michael@0: // Establishes the type of the resultant operation, as well as michael@0: // makes the operator the correct one for the operands. michael@0: // michael@0: // Returns false if operator can't work on operands. michael@0: // michael@0: bool TIntermBinary::promote(TInfoSink& infoSink) michael@0: { michael@0: // This function only handles scalars, vectors, and matrices. michael@0: if (left->isArray() || right->isArray()) { michael@0: infoSink.info.message(EPrefixInternalError, getLine(), "Invalid operation for arrays"); michael@0: return false; michael@0: } michael@0: michael@0: // GLSL ES 2.0 does not support implicit type casting. michael@0: // So the basic type should always match. michael@0: if (left->getBasicType() != right->getBasicType()) michael@0: return false; michael@0: michael@0: // michael@0: // Base assumption: just make the type the same as the left michael@0: // operand. Then only deviations from this need be coded. michael@0: // michael@0: setType(left->getType()); michael@0: michael@0: // The result gets promoted to the highest precision. michael@0: TPrecision higherPrecision = GetHigherPrecision(left->getPrecision(), right->getPrecision()); michael@0: getTypePointer()->setPrecision(higherPrecision); michael@0: michael@0: // Binary operations results in temporary variables unless both michael@0: // operands are const. michael@0: if (left->getQualifier() != EvqConst || right->getQualifier() != EvqConst) { michael@0: getTypePointer()->setQualifier(EvqTemporary); michael@0: } michael@0: michael@0: int size = std::max(left->getNominalSize(), right->getNominalSize()); michael@0: michael@0: // michael@0: // All scalars. Code after this test assumes this case is removed! michael@0: // michael@0: if (size == 1) { michael@0: switch (op) { michael@0: // michael@0: // Promote to conditional michael@0: // michael@0: case EOpEqual: michael@0: case EOpNotEqual: michael@0: case EOpLessThan: michael@0: case EOpGreaterThan: michael@0: case EOpLessThanEqual: michael@0: case EOpGreaterThanEqual: michael@0: setType(TType(EbtBool, EbpUndefined)); michael@0: break; michael@0: michael@0: // michael@0: // And and Or operate on conditionals michael@0: // michael@0: case EOpLogicalAnd: michael@0: case EOpLogicalOr: michael@0: // Both operands must be of type bool. michael@0: if (left->getBasicType() != EbtBool || right->getBasicType() != EbtBool) michael@0: return false; michael@0: setType(TType(EbtBool, EbpUndefined)); michael@0: break; michael@0: michael@0: default: michael@0: break; michael@0: } michael@0: return true; michael@0: } michael@0: michael@0: // If we reach here, at least one of the operands is vector or matrix. michael@0: // The other operand could be a scalar, vector, or matrix. michael@0: // Are the sizes compatible? michael@0: // michael@0: if (left->getNominalSize() != right->getNominalSize()) { michael@0: // If the nominal size of operands do not match: michael@0: // One of them must be scalar. michael@0: if (left->getNominalSize() != 1 && right->getNominalSize() != 1) michael@0: return false; michael@0: // Operator cannot be of type pure assignment. michael@0: if (op == EOpAssign || op == EOpInitialize) michael@0: return false; michael@0: } michael@0: michael@0: // michael@0: // Can these two operands be combined? michael@0: // michael@0: TBasicType basicType = left->getBasicType(); michael@0: switch (op) { michael@0: case EOpMul: michael@0: if (!left->isMatrix() && right->isMatrix()) { michael@0: if (left->isVector()) michael@0: op = EOpVectorTimesMatrix; michael@0: else { michael@0: op = EOpMatrixTimesScalar; michael@0: setType(TType(basicType, higherPrecision, EvqTemporary, size, true)); michael@0: } michael@0: } else if (left->isMatrix() && !right->isMatrix()) { michael@0: if (right->isVector()) { michael@0: op = EOpMatrixTimesVector; michael@0: setType(TType(basicType, higherPrecision, EvqTemporary, size, false)); michael@0: } else { michael@0: op = EOpMatrixTimesScalar; michael@0: } michael@0: } else if (left->isMatrix() && right->isMatrix()) { michael@0: op = EOpMatrixTimesMatrix; michael@0: } else if (!left->isMatrix() && !right->isMatrix()) { michael@0: if (left->isVector() && right->isVector()) { michael@0: // leave as component product michael@0: } else if (left->isVector() || right->isVector()) { michael@0: op = EOpVectorTimesScalar; michael@0: setType(TType(basicType, higherPrecision, EvqTemporary, size, false)); michael@0: } michael@0: } else { michael@0: infoSink.info.message(EPrefixInternalError, getLine(), "Missing elses"); michael@0: return false; michael@0: } michael@0: break; michael@0: case EOpMulAssign: michael@0: if (!left->isMatrix() && right->isMatrix()) { michael@0: if (left->isVector()) michael@0: op = EOpVectorTimesMatrixAssign; michael@0: else { michael@0: return false; michael@0: } michael@0: } else if (left->isMatrix() && !right->isMatrix()) { michael@0: if (right->isVector()) { michael@0: return false; michael@0: } else { michael@0: op = EOpMatrixTimesScalarAssign; michael@0: } michael@0: } else if (left->isMatrix() && right->isMatrix()) { michael@0: op = EOpMatrixTimesMatrixAssign; michael@0: } else if (!left->isMatrix() && !right->isMatrix()) { michael@0: if (left->isVector() && right->isVector()) { michael@0: // leave as component product michael@0: } else if (left->isVector() || right->isVector()) { michael@0: if (! left->isVector()) michael@0: return false; michael@0: op = EOpVectorTimesScalarAssign; michael@0: setType(TType(basicType, higherPrecision, EvqTemporary, size, false)); michael@0: } michael@0: } else { michael@0: infoSink.info.message(EPrefixInternalError, getLine(), "Missing elses"); michael@0: return false; michael@0: } michael@0: break; michael@0: michael@0: case EOpAssign: michael@0: case EOpInitialize: michael@0: case EOpAdd: michael@0: case EOpSub: michael@0: case EOpDiv: michael@0: case EOpAddAssign: michael@0: case EOpSubAssign: michael@0: case EOpDivAssign: michael@0: if ((left->isMatrix() && right->isVector()) || michael@0: (left->isVector() && right->isMatrix())) michael@0: return false; michael@0: setType(TType(basicType, higherPrecision, EvqTemporary, size, left->isMatrix() || right->isMatrix())); michael@0: break; michael@0: michael@0: case EOpEqual: michael@0: case EOpNotEqual: michael@0: case EOpLessThan: michael@0: case EOpGreaterThan: michael@0: case EOpLessThanEqual: michael@0: case EOpGreaterThanEqual: michael@0: if ((left->isMatrix() && right->isVector()) || michael@0: (left->isVector() && right->isMatrix())) michael@0: return false; michael@0: setType(TType(EbtBool, EbpUndefined)); michael@0: break; michael@0: michael@0: default: michael@0: return false; michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: michael@0: bool CompareStruct(const TType& leftNodeType, ConstantUnion* rightUnionArray, ConstantUnion* leftUnionArray) michael@0: { michael@0: const TFieldList& fields = leftNodeType.getStruct()->fields(); michael@0: michael@0: size_t structSize = fields.size(); michael@0: size_t index = 0; michael@0: michael@0: for (size_t j = 0; j < structSize; j++) { michael@0: size_t size = fields[j]->type()->getObjectSize(); michael@0: for (size_t i = 0; i < size; i++) { michael@0: if (fields[j]->type()->getBasicType() == EbtStruct) { michael@0: if (!CompareStructure(*(fields[j]->type()), &rightUnionArray[index], &leftUnionArray[index])) michael@0: return false; michael@0: } else { michael@0: if (leftUnionArray[index] != rightUnionArray[index]) michael@0: return false; michael@0: index++; michael@0: } michael@0: } michael@0: } michael@0: return true; michael@0: } michael@0: michael@0: bool CompareStructure(const TType& leftNodeType, ConstantUnion* rightUnionArray, ConstantUnion* leftUnionArray) michael@0: { michael@0: if (leftNodeType.isArray()) { michael@0: TType typeWithoutArrayness = leftNodeType; michael@0: typeWithoutArrayness.clearArrayness(); michael@0: michael@0: size_t arraySize = leftNodeType.getArraySize(); michael@0: michael@0: for (size_t i = 0; i < arraySize; ++i) { michael@0: size_t offset = typeWithoutArrayness.getObjectSize() * i; michael@0: if (!CompareStruct(typeWithoutArrayness, &rightUnionArray[offset], &leftUnionArray[offset])) michael@0: return false; michael@0: } michael@0: } else michael@0: return CompareStruct(leftNodeType, rightUnionArray, leftUnionArray); michael@0: michael@0: return true; michael@0: } michael@0: michael@0: // michael@0: // The fold functions see if an operation on a constant can be done in place, michael@0: // without generating run-time code. michael@0: // michael@0: // Returns the node to keep using, which may or may not be the node passed in. michael@0: // michael@0: michael@0: TIntermTyped* TIntermConstantUnion::fold(TOperator op, TIntermTyped* constantNode, TInfoSink& infoSink) michael@0: { michael@0: ConstantUnion *unionArray = getUnionArrayPointer(); michael@0: size_t objectSize = getType().getObjectSize(); michael@0: michael@0: if (constantNode) { // binary operations michael@0: TIntermConstantUnion *node = constantNode->getAsConstantUnion(); michael@0: ConstantUnion *rightUnionArray = node->getUnionArrayPointer(); michael@0: TType returnType = getType(); michael@0: michael@0: // for a case like float f = 1.2 + vec4(2,3,4,5); michael@0: if (constantNode->getType().getObjectSize() == 1 && objectSize > 1) { michael@0: rightUnionArray = new ConstantUnion[objectSize]; michael@0: for (size_t i = 0; i < objectSize; ++i) michael@0: rightUnionArray[i] = *node->getUnionArrayPointer(); michael@0: returnType = getType(); michael@0: } else if (constantNode->getType().getObjectSize() > 1 && objectSize == 1) { michael@0: // for a case like float f = vec4(2,3,4,5) + 1.2; michael@0: unionArray = new ConstantUnion[constantNode->getType().getObjectSize()]; michael@0: for (size_t i = 0; i < constantNode->getType().getObjectSize(); ++i) michael@0: unionArray[i] = *getUnionArrayPointer(); michael@0: returnType = node->getType(); michael@0: objectSize = constantNode->getType().getObjectSize(); michael@0: } michael@0: michael@0: ConstantUnion* tempConstArray = 0; michael@0: TIntermConstantUnion *tempNode; michael@0: michael@0: bool boolNodeFlag = false; michael@0: switch(op) { michael@0: case EOpAdd: michael@0: tempConstArray = new ConstantUnion[objectSize]; michael@0: {// support MSVC++6.0 michael@0: for (size_t i = 0; i < objectSize; i++) michael@0: tempConstArray[i] = unionArray[i] + rightUnionArray[i]; michael@0: } michael@0: break; michael@0: case EOpSub: michael@0: tempConstArray = new ConstantUnion[objectSize]; michael@0: {// support MSVC++6.0 michael@0: for (size_t i = 0; i < objectSize; i++) michael@0: tempConstArray[i] = unionArray[i] - rightUnionArray[i]; michael@0: } michael@0: break; michael@0: michael@0: case EOpMul: michael@0: case EOpVectorTimesScalar: michael@0: case EOpMatrixTimesScalar: michael@0: tempConstArray = new ConstantUnion[objectSize]; michael@0: {// support MSVC++6.0 michael@0: for (size_t i = 0; i < objectSize; i++) michael@0: tempConstArray[i] = unionArray[i] * rightUnionArray[i]; michael@0: } michael@0: break; michael@0: case EOpMatrixTimesMatrix: michael@0: if (getType().getBasicType() != EbtFloat || node->getBasicType() != EbtFloat) { michael@0: infoSink.info.message(EPrefixInternalError, getLine(), "Constant Folding cannot be done for matrix multiply"); michael@0: return 0; michael@0: } michael@0: {// support MSVC++6.0 michael@0: int size = getNominalSize(); michael@0: tempConstArray = new ConstantUnion[size*size]; michael@0: for (int row = 0; row < size; row++) { michael@0: for (int column = 0; column < size; column++) { michael@0: tempConstArray[size * column + row].setFConst(0.0f); michael@0: for (int i = 0; i < size; i++) { michael@0: tempConstArray[size * column + row].setFConst(tempConstArray[size * column + row].getFConst() + unionArray[i * size + row].getFConst() * (rightUnionArray[column * size + i].getFConst())); michael@0: } michael@0: } michael@0: } michael@0: } michael@0: break; michael@0: case EOpDiv: michael@0: tempConstArray = new ConstantUnion[objectSize]; michael@0: {// support MSVC++6.0 michael@0: for (size_t i = 0; i < objectSize; i++) { michael@0: switch (getType().getBasicType()) { michael@0: case EbtFloat: michael@0: if (rightUnionArray[i] == 0.0f) { michael@0: infoSink.info.message(EPrefixWarning, getLine(), "Divide by zero error during constant folding"); michael@0: tempConstArray[i].setFConst(unionArray[i].getFConst() < 0 ? -FLT_MAX : FLT_MAX); michael@0: } else michael@0: tempConstArray[i].setFConst(unionArray[i].getFConst() / rightUnionArray[i].getFConst()); michael@0: break; michael@0: michael@0: case EbtInt: michael@0: if (rightUnionArray[i] == 0) { michael@0: infoSink.info.message(EPrefixWarning, getLine(), "Divide by zero error during constant folding"); michael@0: tempConstArray[i].setIConst(INT_MAX); michael@0: } else michael@0: tempConstArray[i].setIConst(unionArray[i].getIConst() / rightUnionArray[i].getIConst()); michael@0: break; michael@0: default: michael@0: infoSink.info.message(EPrefixInternalError, getLine(), "Constant folding cannot be done for \"/\""); michael@0: return 0; michael@0: } michael@0: } michael@0: } michael@0: break; michael@0: michael@0: case EOpMatrixTimesVector: michael@0: if (node->getBasicType() != EbtFloat) { michael@0: infoSink.info.message(EPrefixInternalError, getLine(), "Constant Folding cannot be done for matrix times vector"); michael@0: return 0; michael@0: } michael@0: tempConstArray = new ConstantUnion[getNominalSize()]; michael@0: michael@0: {// support MSVC++6.0 michael@0: for (int size = getNominalSize(), i = 0; i < size; i++) { michael@0: tempConstArray[i].setFConst(0.0f); michael@0: for (int j = 0; j < size; j++) { michael@0: tempConstArray[i].setFConst(tempConstArray[i].getFConst() + ((unionArray[j*size + i].getFConst()) * rightUnionArray[j].getFConst())); michael@0: } michael@0: } michael@0: } michael@0: michael@0: tempNode = new TIntermConstantUnion(tempConstArray, node->getType()); michael@0: tempNode->setLine(getLine()); michael@0: michael@0: return tempNode; michael@0: michael@0: case EOpVectorTimesMatrix: michael@0: if (getType().getBasicType() != EbtFloat) { michael@0: infoSink.info.message(EPrefixInternalError, getLine(), "Constant Folding cannot be done for vector times matrix"); michael@0: return 0; michael@0: } michael@0: michael@0: tempConstArray = new ConstantUnion[getNominalSize()]; michael@0: {// support MSVC++6.0 michael@0: for (int size = getNominalSize(), i = 0; i < size; i++) { michael@0: tempConstArray[i].setFConst(0.0f); michael@0: for (int j = 0; j < size; j++) { michael@0: tempConstArray[i].setFConst(tempConstArray[i].getFConst() + ((unionArray[j].getFConst()) * rightUnionArray[i*size + j].getFConst())); michael@0: } michael@0: } michael@0: } michael@0: break; michael@0: michael@0: case EOpLogicalAnd: // this code is written for possible future use, will not get executed currently michael@0: tempConstArray = new ConstantUnion[objectSize]; michael@0: {// support MSVC++6.0 michael@0: for (size_t i = 0; i < objectSize; i++) michael@0: tempConstArray[i] = unionArray[i] && rightUnionArray[i]; michael@0: } michael@0: break; michael@0: michael@0: case EOpLogicalOr: // this code is written for possible future use, will not get executed currently michael@0: tempConstArray = new ConstantUnion[objectSize]; michael@0: {// support MSVC++6.0 michael@0: for (size_t i = 0; i < objectSize; i++) michael@0: tempConstArray[i] = unionArray[i] || rightUnionArray[i]; michael@0: } michael@0: break; michael@0: michael@0: case EOpLogicalXor: michael@0: tempConstArray = new ConstantUnion[objectSize]; michael@0: {// support MSVC++6.0 michael@0: for (size_t i = 0; i < objectSize; i++) michael@0: switch (getType().getBasicType()) { michael@0: case EbtBool: tempConstArray[i].setBConst((unionArray[i] == rightUnionArray[i]) ? false : true); break; michael@0: default: assert(false && "Default missing"); michael@0: } michael@0: } michael@0: break; michael@0: michael@0: case EOpLessThan: michael@0: assert(objectSize == 1); michael@0: tempConstArray = new ConstantUnion[1]; michael@0: tempConstArray->setBConst(*unionArray < *rightUnionArray); michael@0: returnType = TType(EbtBool, EbpUndefined, EvqConst); michael@0: break; michael@0: case EOpGreaterThan: michael@0: assert(objectSize == 1); michael@0: tempConstArray = new ConstantUnion[1]; michael@0: tempConstArray->setBConst(*unionArray > *rightUnionArray); michael@0: returnType = TType(EbtBool, EbpUndefined, EvqConst); michael@0: break; michael@0: case EOpLessThanEqual: michael@0: { michael@0: assert(objectSize == 1); michael@0: ConstantUnion constant; michael@0: constant.setBConst(*unionArray > *rightUnionArray); michael@0: tempConstArray = new ConstantUnion[1]; michael@0: tempConstArray->setBConst(!constant.getBConst()); michael@0: returnType = TType(EbtBool, EbpUndefined, EvqConst); michael@0: break; michael@0: } michael@0: case EOpGreaterThanEqual: michael@0: { michael@0: assert(objectSize == 1); michael@0: ConstantUnion constant; michael@0: constant.setBConst(*unionArray < *rightUnionArray); michael@0: tempConstArray = new ConstantUnion[1]; michael@0: tempConstArray->setBConst(!constant.getBConst()); michael@0: returnType = TType(EbtBool, EbpUndefined, EvqConst); michael@0: break; michael@0: } michael@0: michael@0: case EOpEqual: michael@0: if (getType().getBasicType() == EbtStruct) { michael@0: if (!CompareStructure(node->getType(), node->getUnionArrayPointer(), unionArray)) michael@0: boolNodeFlag = true; michael@0: } else { michael@0: for (size_t i = 0; i < objectSize; i++) { michael@0: if (unionArray[i] != rightUnionArray[i]) { michael@0: boolNodeFlag = true; michael@0: break; // break out of for loop michael@0: } michael@0: } michael@0: } michael@0: michael@0: tempConstArray = new ConstantUnion[1]; michael@0: if (!boolNodeFlag) { michael@0: tempConstArray->setBConst(true); michael@0: } michael@0: else { michael@0: tempConstArray->setBConst(false); michael@0: } michael@0: michael@0: tempNode = new TIntermConstantUnion(tempConstArray, TType(EbtBool, EbpUndefined, EvqConst)); michael@0: tempNode->setLine(getLine()); michael@0: michael@0: return tempNode; michael@0: michael@0: case EOpNotEqual: michael@0: if (getType().getBasicType() == EbtStruct) { michael@0: if (CompareStructure(node->getType(), node->getUnionArrayPointer(), unionArray)) michael@0: boolNodeFlag = true; michael@0: } else { michael@0: for (size_t i = 0; i < objectSize; i++) { michael@0: if (unionArray[i] == rightUnionArray[i]) { michael@0: boolNodeFlag = true; michael@0: break; // break out of for loop michael@0: } michael@0: } michael@0: } michael@0: michael@0: tempConstArray = new ConstantUnion[1]; michael@0: if (!boolNodeFlag) { michael@0: tempConstArray->setBConst(true); michael@0: } michael@0: else { michael@0: tempConstArray->setBConst(false); michael@0: } michael@0: michael@0: tempNode = new TIntermConstantUnion(tempConstArray, TType(EbtBool, EbpUndefined, EvqConst)); michael@0: tempNode->setLine(getLine()); michael@0: michael@0: return tempNode; michael@0: michael@0: default: michael@0: infoSink.info.message(EPrefixInternalError, getLine(), "Invalid operator for constant folding"); michael@0: return 0; michael@0: } michael@0: tempNode = new TIntermConstantUnion(tempConstArray, returnType); michael@0: tempNode->setLine(getLine()); michael@0: michael@0: return tempNode; michael@0: } else { michael@0: // michael@0: // Do unary operations michael@0: // michael@0: TIntermConstantUnion *newNode = 0; michael@0: ConstantUnion* tempConstArray = new ConstantUnion[objectSize]; michael@0: for (size_t i = 0; i < objectSize; i++) { michael@0: switch(op) { michael@0: case EOpNegative: michael@0: switch (getType().getBasicType()) { michael@0: case EbtFloat: tempConstArray[i].setFConst(-unionArray[i].getFConst()); break; michael@0: case EbtInt: tempConstArray[i].setIConst(-unionArray[i].getIConst()); break; michael@0: default: michael@0: infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant"); michael@0: return 0; michael@0: } michael@0: break; michael@0: case EOpLogicalNot: // this code is written for possible future use, will not get executed currently michael@0: switch (getType().getBasicType()) { michael@0: case EbtBool: tempConstArray[i].setBConst(!unionArray[i].getBConst()); break; michael@0: default: michael@0: infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant"); michael@0: return 0; michael@0: } michael@0: break; michael@0: default: michael@0: return 0; michael@0: } michael@0: } michael@0: newNode = new TIntermConstantUnion(tempConstArray, getType()); michael@0: newNode->setLine(getLine()); michael@0: return newNode; michael@0: } michael@0: } michael@0: michael@0: TIntermTyped* TIntermediate::promoteConstantUnion(TBasicType promoteTo, TIntermConstantUnion* node) michael@0: { michael@0: size_t size = node->getType().getObjectSize(); michael@0: michael@0: ConstantUnion *leftUnionArray = new ConstantUnion[size]; michael@0: michael@0: for (size_t i = 0; i < size; i++) { michael@0: michael@0: switch (promoteTo) { michael@0: case EbtFloat: michael@0: switch (node->getType().getBasicType()) { michael@0: case EbtInt: michael@0: leftUnionArray[i].setFConst(static_cast(node->getIConst(i))); michael@0: break; michael@0: case EbtBool: michael@0: leftUnionArray[i].setFConst(static_cast(node->getBConst(i))); michael@0: break; michael@0: case EbtFloat: michael@0: leftUnionArray[i].setFConst(static_cast(node->getFConst(i))); michael@0: break; michael@0: default: michael@0: infoSink.info.message(EPrefixInternalError, node->getLine(), "Cannot promote"); michael@0: return 0; michael@0: } michael@0: break; michael@0: case EbtInt: michael@0: switch (node->getType().getBasicType()) { michael@0: case EbtInt: michael@0: leftUnionArray[i].setIConst(static_cast(node->getIConst(i))); michael@0: break; michael@0: case EbtBool: michael@0: leftUnionArray[i].setIConst(static_cast(node->getBConst(i))); michael@0: break; michael@0: case EbtFloat: michael@0: leftUnionArray[i].setIConst(static_cast(node->getFConst(i))); michael@0: break; michael@0: default: michael@0: infoSink.info.message(EPrefixInternalError, node->getLine(), "Cannot promote"); michael@0: return 0; michael@0: } michael@0: break; michael@0: case EbtBool: michael@0: switch (node->getType().getBasicType()) { michael@0: case EbtInt: michael@0: leftUnionArray[i].setBConst(node->getIConst(i) != 0); michael@0: break; michael@0: case EbtBool: michael@0: leftUnionArray[i].setBConst(node->getBConst(i)); michael@0: break; michael@0: case EbtFloat: michael@0: leftUnionArray[i].setBConst(node->getFConst(i) != 0.0f); michael@0: break; michael@0: default: michael@0: infoSink.info.message(EPrefixInternalError, node->getLine(), "Cannot promote"); michael@0: return 0; michael@0: } michael@0: michael@0: break; michael@0: default: michael@0: infoSink.info.message(EPrefixInternalError, node->getLine(), "Incorrect data type found"); michael@0: return 0; michael@0: } michael@0: michael@0: } michael@0: michael@0: const TType& t = node->getType(); michael@0: michael@0: return addConstantUnion(leftUnionArray, TType(promoteTo, t.getPrecision(), t.getQualifier(), t.getNominalSize(), t.isMatrix(), t.isArray()), node->getLine()); michael@0: } michael@0: michael@0: // static michael@0: TString TIntermTraverser::hash(const TString& name, ShHashFunction64 hashFunction) michael@0: { michael@0: if (hashFunction == NULL || name.empty()) michael@0: return name; michael@0: khronos_uint64_t number = (*hashFunction)(name.c_str(), name.length()); michael@0: TStringStream stream; michael@0: stream << HASHED_NAME_PREFIX << std::hex << number; michael@0: TString hashedName = stream.str(); michael@0: return hashedName; michael@0: }