// // Do size checking for an array type's size. // // Returns true if there was an error. // bool TParseContext::arraySizeErrorCheck(int line, TIntermTyped* expr, int& size) { TIntermConstantUnion* constant = expr->getAsConstantUnion(); if (constant == 0 || constant->getBasicType() != EbtInt) { error(line, "array size must be a constant integer expression", "", ""); return true; } size = constant->getUnionArrayPointer()->getIConst(); if (size <= 0) { error(line, "array size must be a positive integer", "", ""); size = 1; return true; } return false; }
// // This function returns the tree representation for the vector field(s) being accessed from contant vector. // If only one component of vector is accessed (v.x or v[0] where v is a contant vector), then a contant node is // returned, else an aggregate node is returned (for v.xy). The input to this function could either be the symbol // node or it could be the intermediate tree representation of accessing fields in a constant structure or column of // a constant matrix. // TIntermTyped* TParseContext::addConstVectorNode(TVectorFields& fields, TIntermTyped* node, TSourceLoc line) { TIntermTyped* typedNode; TIntermConstantUnion* tempConstantNode = node->getAsConstantUnion(); ConstantUnion *unionArray; if (tempConstantNode) { unionArray = tempConstantNode->getUnionArrayPointer(); ASSERT(unionArray); if (!unionArray) { return node; } } else { // The node has to be either a symbol node or an aggregate node or a tempConstant node, else, its an error error(line, "Cannot offset into the vector", "Error"); recover(); return 0; } ConstantUnion* constArray = new ConstantUnion[fields.num]; for (int i = 0; i < fields.num; i++) { if (fields.offsets[i] >= node->getType().getObjectSize()) { std::stringstream extraInfoStream; extraInfoStream << "vector field selection out of range '" << fields.offsets[i] << "'"; std::string extraInfo = extraInfoStream.str(); error(line, "", "[", extraInfo.c_str()); recover(); fields.offsets[i] = 0; } constArray[i] = unionArray[fields.offsets[i]]; } typedNode = intermediate.addConstantUnion(constArray, node->getType(), line); return typedNode; }
// // This function returns the tree representation for the vector field(s) being accessed from contant vector. // If only one component of vector is accessed (v.x or v[0] where v is a contant vector), then a contant node is // returned, else an aggregate node is returned (for v.xy). The input to this function could either be the symbol // node or it could be the intermediate tree representation of accessing fields in a constant structure or column of // a constant matrix. // TIntermTyped* TParseContext::addConstVectorNode(TVectorFields& fields, TIntermTyped* node, TSourceLoc line) { TIntermTyped* typedNode; TIntermConstantUnion* tempConstantNode = node->getAsConstantUnion(); ConstantUnion *unionArray; if (tempConstantNode) { unionArray = tempConstantNode->getUnionArrayPointer(); if (!unionArray) { // this error message should never be raised infoSink.info.message(EPrefixInternalError, "ConstantUnion not initialized in addConstVectorNode function", line); recover(); return node; } } else { // The node has to be either a symbol node or an aggregate node or a tempConstant node, else, its an error error(line, "Cannot offset into the vector", "Error", ""); recover(); return 0; } ConstantUnion* constArray = new ConstantUnion[fields.num]; for (int i = 0; i < fields.num; i++) { if (fields.offsets[i] >= node->getType().getObjectSize()) { error(line, "", "[", "vector field selection out of range '%d'", fields.offsets[i]); recover(); fields.offsets[i] = 0; } constArray[i] = unionArray[fields.offsets[i]]; } typedNode = intermediate.addConstantUnion(constArray, node->getType(), line); return typedNode; }
// // This function returns the column being accessed from a constant matrix. The values are retrieved from // the symbol table and parse-tree is built for a vector (each column of a matrix is a vector). The input // to the function could either be a symbol node (m[0] where m is a constant matrix)that represents a // constant matrix or it could be the tree representation of the constant matrix (s.m1[0] where s is a constant structure) // TIntermTyped* TParseContext::addConstMatrixNode(int index, TIntermTyped* node, TSourceLoc line) { TIntermTyped* typedNode; TIntermConstantUnion* tempConstantNode = node->getAsConstantUnion(); if (index >= node->getType().getNominalSize()) { error(line, "", "[", "matrix field selection out of range '%d'", index); recover(); index = 0; } if (tempConstantNode) { ConstantUnion* unionArray = tempConstantNode->getUnionArrayPointer(); int size = tempConstantNode->getType().getNominalSize(); typedNode = intermediate.addConstantUnion(&unionArray[size*index], tempConstantNode->getType(), line); } else { error(line, "Cannot offset into the matrix", "Error", ""); recover(); return 0; } return typedNode; }
bool CollectVariables::visitBinary(Visit, TIntermBinary *binaryNode) { if (binaryNode->getOp() == EOpIndexDirectInterfaceBlock) { // NOTE: we do not determine static use for individual blocks of an array TIntermTyped *blockNode = binaryNode->getLeft()->getAsTyped(); ASSERT(blockNode); TIntermConstantUnion *constantUnion = binaryNode->getRight()->getAsConstantUnion(); ASSERT(constantUnion); const TInterfaceBlock *interfaceBlock = blockNode->getType().getInterfaceBlock(); InterfaceBlock *namedBlock = FindVariable(interfaceBlock->name(), mInterfaceBlocks); ASSERT(namedBlock); namedBlock->staticUse = true; unsigned int fieldIndex = constantUnion->getUConst(0); ASSERT(fieldIndex < namedBlock->fields.size()); namedBlock->fields[fieldIndex].staticUse = true; return false; } return true; }
// // 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, const TSourceLoc &line) { switch (op) { case EOpEqual: case EOpNotEqual: if (left->isArray()) return NULL; break; case EOpLessThan: case EOpGreaterThan: case EOpLessThanEqual: case EOpGreaterThanEqual: if (left->isMatrix() || left->isArray() || left->isVector() || left->getBasicType() == EbtStruct) { return NULL; } break; case EOpLogicalOr: case EOpLogicalXor: case EOpLogicalAnd: if (left->getBasicType() != EbtBool || left->isMatrix() || left->isArray() || left->isVector()) { return NULL; } break; case EOpAdd: case EOpSub: case EOpDiv: case EOpMul: if (left->getBasicType() == EbtStruct || left->getBasicType() == EbtBool) return NULL; default: break; } if (left->getBasicType() != right->getBasicType()) { return NULL; } // // Need a new node holding things together then. Make // one and promote it to the right type. // TIntermBinary *node = new TIntermBinary(op); node->setLine(line); node->setLeft(left); node->setRight(right); if (!node->promote(mInfoSink)) return NULL; // // See if we can fold constants. // TIntermConstantUnion *leftTempConstant = left->getAsConstantUnion(); TIntermConstantUnion *rightTempConstant = right->getAsConstantUnion(); if (leftTempConstant && rightTempConstant) { TIntermTyped *typedReturnNode = leftTempConstant->fold(node->getOp(), rightTempConstant, mInfoSink); if (typedReturnNode) return typedReturnNode; } 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, const TSourceLoc &line) { TIntermUnary *node; TIntermTyped *child = childNode->getAsTyped(); if (child == NULL) { mInfoSink.info.message(EPrefixInternalError, line, "Bad type in AddUnaryMath"); return NULL; } switch (op) { case EOpLogicalNot: if (child->getType().getBasicType() != EbtBool || child->getType().isMatrix() || child->getType().isArray() || child->getType().isVector()) { return NULL; } break; case EOpPostIncrement: case EOpPreIncrement: case EOpPostDecrement: case EOpPreDecrement: case EOpNegative: case EOpPositive: if (child->getType().getBasicType() == EbtStruct || child->getType().isArray()) { return NULL; } default: break; } TIntermConstantUnion *childTempConstant = 0; if (child->getAsConstantUnion()) childTempConstant = child->getAsConstantUnion(); // // Make a new node for the operator. // node = new TIntermUnary(op); node->setLine(line); node->setOperand(child); if (!node->promote(mInfoSink)) return 0; if (childTempConstant) { TIntermTyped *newChild = childTempConstant->fold(op, 0, mInfoSink); if (newChild) return newChild; } return node; }
bool TOutputTraverser::visitBinary(Visit visit, TIntermBinary *node) { TInfoSinkBase& out = sink; OutputTreeText(out, node, mDepth); switch (node->getOp()) { case EOpAssign: out << "move second child to first child"; break; case EOpInitialize: out << "initialize first child with second child"; break; case EOpAddAssign: out << "add second child into first child"; break; case EOpSubAssign: out << "subtract second child into first child"; break; case EOpMulAssign: out << "multiply second child into first child"; break; case EOpVectorTimesMatrixAssign: out << "matrix mult second child into first child"; break; case EOpVectorTimesScalarAssign: out << "vector scale second child into first child"; break; case EOpMatrixTimesScalarAssign: out << "matrix scale second child into first child"; break; case EOpMatrixTimesMatrixAssign: out << "matrix mult second child into first child"; break; case EOpDivAssign: out << "divide second child into first child"; break; case EOpIModAssign: out << "modulo second child into first child"; break; case EOpBitShiftLeftAssign: out << "bit-wise shift first child left by second child"; break; case EOpBitShiftRightAssign: out << "bit-wise shift first child right by second child"; break; case EOpBitwiseAndAssign: out << "bit-wise and second child into first child"; break; case EOpBitwiseXorAssign: out << "bit-wise xor second child into first child"; break; case EOpBitwiseOrAssign: out << "bit-wise or second child into first child"; break; case EOpIndexDirect: out << "direct index"; break; case EOpIndexIndirect: out << "indirect index"; break; case EOpIndexDirectStruct: out << "direct index for structure"; break; case EOpIndexDirectInterfaceBlock: out << "direct index for interface block"; break; case EOpVectorSwizzle: out << "vector swizzle"; break; case EOpAdd: out << "add"; break; case EOpSub: out << "subtract"; break; case EOpMul: out << "component-wise multiply"; break; case EOpDiv: out << "divide"; break; case EOpIMod: out << "modulo"; break; case EOpBitShiftLeft: out << "bit-wise shift left"; break; case EOpBitShiftRight: out << "bit-wise shift right"; break; case EOpBitwiseAnd: out << "bit-wise and"; break; case EOpBitwiseXor: out << "bit-wise xor"; break; case EOpBitwiseOr: out << "bit-wise or"; break; case EOpEqual: out << "Compare Equal"; break; case EOpNotEqual: out << "Compare Not Equal"; break; case EOpLessThan: out << "Compare Less Than"; break; case EOpGreaterThan: out << "Compare Greater Than"; break; case EOpLessThanEqual: out << "Compare Less Than or Equal"; break; case EOpGreaterThanEqual: out << "Compare Greater Than or Equal"; break; case EOpVectorTimesScalar: out << "vector-scale"; break; case EOpVectorTimesMatrix: out << "vector-times-matrix"; break; case EOpMatrixTimesVector: out << "matrix-times-vector"; break; case EOpMatrixTimesScalar: out << "matrix-scale"; break; case EOpMatrixTimesMatrix: out << "matrix-multiply"; break; case EOpLogicalOr: out << "logical-or"; break; case EOpLogicalXor: out << "logical-xor"; break; case EOpLogicalAnd: out << "logical-and"; break; default: out << "<unknown op>"; } out << " (" << node->getCompleteString() << ")"; out << "\n"; // Special handling for direct indexes. Because constant // unions are not aware they are struct indexes, treat them // here where we have that contextual knowledge. if (node->getOp() == EOpIndexDirectStruct || node->getOp() == EOpIndexDirectInterfaceBlock) { mDepth++; node->getLeft()->traverse(this); mDepth--; TIntermConstantUnion *intermConstantUnion = node->getRight()->getAsConstantUnion(); ASSERT(intermConstantUnion); OutputTreeText(out, intermConstantUnion, mDepth + 1); // The following code finds the field name from the constant union const ConstantUnion *constantUnion = intermConstantUnion->getUnionArrayPointer(); const TStructure *structure = node->getLeft()->getType().getStruct(); const TInterfaceBlock *interfaceBlock = node->getLeft()->getType().getInterfaceBlock(); ASSERT(structure || interfaceBlock); const TFieldList &fields = structure ? structure->fields() : interfaceBlock->fields(); const TField *field = fields[constantUnion->getIConst()]; out << constantUnion->getIConst() << " (field '" << field->name() << "')"; return false; } return true; }
// // 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 || child->getType().isArray()) return 0; default: break; } // // Do we need to promote the operand? // // Note: Implicit promotions were removed from the language. // TBasicType newType = EbtVoid; switch (op) { case EOpConstructInt: newType = EbtInt; break; case EOpConstructBool: newType = EbtBool; break; case EOpConstructFloat: newType = EbtFloat; break; default: break; } if (newType != EbtVoid) { child = addConversion(op, TType(newType, child->getPrecision(), 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; } TIntermConstantUnion *childTempConstant = 0; if (child->getAsConstantUnion()) 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); if (newChild) return newChild; } 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 EOpEqual: case EOpNotEqual: if (left->isArray()) return 0; break; case EOpLessThan: case EOpGreaterThan: case EOpLessThanEqual: case EOpGreaterThanEqual: if (left->isMatrix() || left->isArray() || left->isVector() || left->getBasicType() == EbtStruct) { return 0; } break; case EOpLogicalOr: case EOpLogicalXor: case EOpLogicalAnd: if (left->getBasicType() != EbtBool || left->isMatrix() || left->isArray() || left->isVector()) { return 0; } break; case EOpAdd: case EOpSub: case EOpDiv: case EOpMul: if (left->getBasicType() == EbtStruct || left->getBasicType() == EbtBool) return 0; default: break; } // // First try converting the children to compatible types. // if (left->getType().getStruct() && right->getType().getStruct()) { if (left->getType() != right->getType()) return 0; } else { TIntermTyped* child = addConversion(op, left->getType(), right); if (child) right = child; else { child = addConversion(op, right->getType(), left); if (child) left = child; else return 0; } } // // 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; // // See if we can fold constants. // TIntermTyped* typedReturnNode = 0; TIntermConstantUnion *leftTempConstant = left->getAsConstantUnion(); TIntermConstantUnion *rightTempConstant = right->getAsConstantUnion(); if (leftTempConstant && rightTempConstant) { typedReturnNode = leftTempConstant->fold(node->getOp(), rightTempConstant, infoSink); if (typedReturnNode) return typedReturnNode; } return node; }
TIntermTyped* TIntermConstantUnion::fold(TOperator op, TIntermTyped* constantNode, TInfoSink& infoSink) { ConstantUnion *unionArray = getUnionArrayPointer(); int objectSize = getType().getObjectSize(); if (constantNode) { // binary operations TIntermConstantUnion *node = constantNode->getAsConstantUnion(); ConstantUnion *rightUnionArray = node->getUnionArrayPointer(); TType returnType = getType(); // for a case like float f = 1.2 + vec4(2,3,4,5); if (constantNode->getType().getObjectSize() == 1 && objectSize > 1) { rightUnionArray = new ConstantUnion[objectSize]; for (int i = 0; i < objectSize; ++i) rightUnionArray[i] = *node->getUnionArrayPointer(); returnType = getType(); } else if (constantNode->getType().getObjectSize() > 1 && objectSize == 1) { // for a case like float f = vec4(2,3,4,5) + 1.2; unionArray = new ConstantUnion[constantNode->getType().getObjectSize()]; for (int i = 0; i < constantNode->getType().getObjectSize(); ++i) unionArray[i] = *getUnionArrayPointer(); returnType = node->getType(); objectSize = constantNode->getType().getObjectSize(); } ConstantUnion* tempConstArray = 0; TIntermConstantUnion *tempNode; bool boolNodeFlag = false; switch(op) { case EOpAdd: tempConstArray = new ConstantUnion[objectSize]; {// support MSVC++6.0 for (int i = 0; i < objectSize; i++) tempConstArray[i] = unionArray[i] + rightUnionArray[i]; } break; case EOpSub: tempConstArray = new ConstantUnion[objectSize]; {// support MSVC++6.0 for (int i = 0; i < objectSize; i++) tempConstArray[i] = unionArray[i] - rightUnionArray[i]; } break; case EOpMul: case EOpVectorTimesScalar: case EOpMatrixTimesScalar: tempConstArray = new ConstantUnion[objectSize]; {// support MSVC++6.0 for (int i = 0; i < objectSize; i++) tempConstArray[i] = unionArray[i] * rightUnionArray[i]; } break; case EOpMatrixTimesMatrix: if (getType().getBasicType() != EbtFloat || node->getBasicType() != EbtFloat) { infoSink.info.message(EPrefixInternalError, "Constant Folding cannot be done for matrix multiply", getLine()); return 0; } {// support MSVC++6.0 int size = getNominalSize(); tempConstArray = new ConstantUnion[size*size]; for (int row = 0; row < size; row++) { for (int column = 0; column < size; column++) { tempConstArray[size * column + row].setFConst(0.0f); for (int i = 0; i < size; i++) { tempConstArray[size * column + row].setFConst(tempConstArray[size * column + row].getFConst() + unionArray[i * size + row].getFConst() * (rightUnionArray[column * size + i].getFConst())); } } } } break; case EOpDiv: tempConstArray = new ConstantUnion[objectSize]; {// support MSVC++6.0 for (int i = 0; i < objectSize; i++) { switch (getType().getBasicType()) { case EbtFloat: if (rightUnionArray[i] == 0.0f) { infoSink.info.message(EPrefixWarning, "Divide by zero error during constant folding", getLine()); tempConstArray[i].setFConst(FLT_MAX); } else tempConstArray[i].setFConst(unionArray[i].getFConst() / rightUnionArray[i].getFConst()); break; case EbtInt: if (rightUnionArray[i] == 0) { infoSink.info.message(EPrefixWarning, "Divide by zero error during constant folding", getLine()); tempConstArray[i].setIConst(INT_MAX); } else tempConstArray[i].setIConst(unionArray[i].getIConst() / rightUnionArray[i].getIConst()); break; default: infoSink.info.message(EPrefixInternalError, "Constant folding cannot be done for \"/\"", getLine()); return 0; } } } break; case EOpMatrixTimesVector: if (node->getBasicType() != EbtFloat) { infoSink.info.message(EPrefixInternalError, "Constant Folding cannot be done for matrix times vector", getLine()); return 0; } tempConstArray = new ConstantUnion[getNominalSize()]; {// support MSVC++6.0 for (int size = getNominalSize(), i = 0; i < size; i++) { tempConstArray[i].setFConst(0.0f); for (int j = 0; j < size; j++) { tempConstArray[i].setFConst(tempConstArray[i].getFConst() + ((unionArray[j*size + i].getFConst()) * rightUnionArray[j].getFConst())); } } } tempNode = new TIntermConstantUnion(tempConstArray, node->getType()); tempNode->setLine(getLine()); return tempNode; case EOpVectorTimesMatrix: if (getType().getBasicType() != EbtFloat) { infoSink.info.message(EPrefixInternalError, "Constant Folding cannot be done for vector times matrix", getLine()); return 0; } tempConstArray = new ConstantUnion[getNominalSize()]; {// support MSVC++6.0 for (int size = getNominalSize(), i = 0; i < size; i++) { tempConstArray[i].setFConst(0.0f); for (int j = 0; j < size; j++) { tempConstArray[i].setFConst(tempConstArray[i].getFConst() + ((unionArray[j].getFConst()) * rightUnionArray[i*size + j].getFConst())); } } } break; case EOpLogicalAnd: // this code is written for possible future use, will not get executed currently tempConstArray = new ConstantUnion[objectSize]; {// support MSVC++6.0 for (int i = 0; i < objectSize; i++) tempConstArray[i] = unionArray[i] && rightUnionArray[i]; } break; case EOpLogicalOr: // this code is written for possible future use, will not get executed currently tempConstArray = new ConstantUnion[objectSize]; {// support MSVC++6.0 for (int i = 0; i < objectSize; i++) tempConstArray[i] = unionArray[i] || rightUnionArray[i]; } break; case EOpLogicalXor: tempConstArray = new ConstantUnion[objectSize]; {// support MSVC++6.0 for (int i = 0; i < objectSize; i++) switch (getType().getBasicType()) { case EbtBool: tempConstArray[i].setBConst((unionArray[i] == rightUnionArray[i]) ? false : true); break; default: assert(false && "Default missing"); } } break; case EOpLessThan: assert(objectSize == 1); tempConstArray = new ConstantUnion[1]; tempConstArray->setBConst(*unionArray < *rightUnionArray); returnType = TType(EbtBool, EbpUndefined, EvqConst); break; case EOpGreaterThan: assert(objectSize == 1); tempConstArray = new ConstantUnion[1]; tempConstArray->setBConst(*unionArray > *rightUnionArray); returnType = TType(EbtBool, EbpUndefined, EvqConst); break; case EOpLessThanEqual: { assert(objectSize == 1); ConstantUnion constant; constant.setBConst(*unionArray > *rightUnionArray); tempConstArray = new ConstantUnion[1]; tempConstArray->setBConst(!constant.getBConst()); returnType = TType(EbtBool, EbpUndefined, EvqConst); break; } case EOpGreaterThanEqual: { assert(objectSize == 1); ConstantUnion constant; constant.setBConst(*unionArray < *rightUnionArray); tempConstArray = new ConstantUnion[1]; tempConstArray->setBConst(!constant.getBConst()); returnType = TType(EbtBool, EbpUndefined, EvqConst); break; } case EOpEqual: if (getType().getBasicType() == EbtStruct) { if (!CompareStructure(node->getType(), node->getUnionArrayPointer(), unionArray)) boolNodeFlag = true; } else { for (int i = 0; i < objectSize; i++) { if (unionArray[i] != rightUnionArray[i]) { boolNodeFlag = true; break; // break out of for loop } } } tempConstArray = new ConstantUnion[1]; if (!boolNodeFlag) { tempConstArray->setBConst(true); } else { tempConstArray->setBConst(false); } tempNode = new TIntermConstantUnion(tempConstArray, TType(EbtBool, EbpUndefined, EvqConst)); tempNode->setLine(getLine()); return tempNode; case EOpNotEqual: if (getType().getBasicType() == EbtStruct) { if (CompareStructure(node->getType(), node->getUnionArrayPointer(), unionArray)) boolNodeFlag = true; } else { for (int i = 0; i < objectSize; i++) { if (unionArray[i] == rightUnionArray[i]) { boolNodeFlag = true; break; // break out of for loop } } } tempConstArray = new ConstantUnion[1]; if (!boolNodeFlag) { tempConstArray->setBConst(true); } else { tempConstArray->setBConst(false); } tempNode = new TIntermConstantUnion(tempConstArray, TType(EbtBool, EbpUndefined, EvqConst)); tempNode->setLine(getLine()); return tempNode; default: infoSink.info.message(EPrefixInternalError, "Invalid operator for constant folding", getLine()); return 0; } tempNode = new TIntermConstantUnion(tempConstArray, returnType); tempNode->setLine(getLine()); return tempNode; } else { // // Do unary operations // TIntermConstantUnion *newNode = 0; ConstantUnion* tempConstArray = new ConstantUnion[objectSize]; for (int i = 0; i < objectSize; i++) { switch(op) { case EOpNegative: switch (getType().getBasicType()) { case EbtFloat: tempConstArray[i].setFConst(-unionArray[i].getFConst()); break; case EbtInt: tempConstArray[i].setIConst(-unionArray[i].getIConst()); break; default: infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant", getLine()); return 0; } break; case EOpLogicalNot: // this code is written for possible future use, will not get executed currently switch (getType().getBasicType()) { case EbtBool: tempConstArray[i].setBConst(!unionArray[i].getBConst()); break; default: infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant", getLine()); return 0; } break; default: return 0; } } newNode = new TIntermConstantUnion(tempConstArray, getType()); newNode->setLine(getLine()); return newNode; } }
bool TOutputGLSLBase::visitBinary(Visit visit, TIntermBinary* node) { bool visitChildren = true; TInfoSinkBase& out = objSink(); switch (node->getOp()) { case EOpInitialize: if (visit == InVisit) { out << " = "; // RHS of initialize is not being declared. mDeclaringVariables = false; } break; case EOpAssign: writeTriplet(visit, "(", " = ", ")"); break; case EOpAddAssign: writeTriplet(visit, "(", " += ", ")"); break; case EOpSubAssign: writeTriplet(visit, "(", " -= ", ")"); break; case EOpDivAssign: writeTriplet(visit, "(", " /= ", ")"); break; // Notice the fall-through. case EOpMulAssign: case EOpVectorTimesMatrixAssign: case EOpVectorTimesScalarAssign: case EOpMatrixTimesScalarAssign: case EOpMatrixTimesMatrixAssign: writeTriplet(visit, "(", " *= ", ")"); break; case EOpIndexDirect: writeTriplet(visit, NULL, "[", "]"); break; case EOpIndexIndirect: if (node->getAddIndexClamp()) { if (visit == InVisit) { if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC) { out << "[int(clamp(float("; } else { out << "[webgl_int_clamp("; } } else if (visit == PostVisit) { int maxSize; TIntermTyped *left = node->getLeft(); TType leftType = left->getType(); if (left->isArray()) { // The shader will fail validation if the array length is not > 0. maxSize = leftType.getArraySize() - 1; } else { maxSize = leftType.getNominalSize() - 1; } if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC) { out << "), 0.0, float(" << maxSize << ")))]"; } else { out << ", 0, " << maxSize << ")]"; } } } else { writeTriplet(visit, NULL, "[", "]"); } break; case EOpIndexDirectStruct: if (visit == InVisit) { out << "."; // TODO(alokp): ASSERT TString fieldName = node->getType().getFieldName(); const TType& structType = node->getLeft()->getType(); if (!mSymbolTable.findBuiltIn(structType.getTypeName())) fieldName = hashName(fieldName); out << fieldName; visitChildren = false; } break; case EOpVectorSwizzle: if (visit == InVisit) { out << "."; TIntermAggregate* rightChild = node->getRight()->getAsAggregate(); TIntermSequence& sequence = rightChild->getSequence(); for (TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); ++sit) { TIntermConstantUnion* element = (*sit)->getAsConstantUnion(); ASSERT(element->getBasicType() == EbtInt); ASSERT(element->getNominalSize() == 1); const ConstantUnion& data = element->getUnionArrayPointer()[0]; ASSERT(data.getType() == EbtInt); switch (data.getIConst()) { case 0: out << "x"; break; case 1: out << "y"; break; case 2: out << "z"; break; case 3: out << "w"; break; default: UNREACHABLE(); break; } } visitChildren = false; } break; case EOpAdd: writeTriplet(visit, "(", " + ", ")"); break; case EOpSub: writeTriplet(visit, "(", " - ", ")"); break; case EOpMul: writeTriplet(visit, "(", " * ", ")"); break; case EOpDiv: writeTriplet(visit, "(", " / ", ")"); break; case EOpMod: UNIMPLEMENTED(); break; case EOpEqual: writeTriplet(visit, "(", " == ", ")"); break; case EOpNotEqual: writeTriplet(visit, "(", " != ", ")"); break; case EOpLessThan: writeTriplet(visit, "(", " < ", ")"); break; case EOpGreaterThan: writeTriplet(visit, "(", " > ", ")"); break; case EOpLessThanEqual: writeTriplet(visit, "(", " <= ", ")"); break; case EOpGreaterThanEqual: writeTriplet(visit, "(", " >= ", ")"); break; // Notice the fall-through. case EOpVectorTimesScalar: case EOpVectorTimesMatrix: case EOpMatrixTimesVector: case EOpMatrixTimesScalar: case EOpMatrixTimesMatrix: writeTriplet(visit, "(", " * ", ")"); break; case EOpLogicalOr: writeTriplet(visit, "(", " || ", ")"); break; case EOpLogicalXor: writeTriplet(visit, "(", " ^^ ", ")"); break; case EOpLogicalAnd: writeTriplet(visit, "(", " && ", ")"); break; default: UNREACHABLE(); break; } return visitChildren; }
// // Do constant folding for an aggregate node that has all its children // as constants and an operator that requires constant folding. // TIntermTyped* TIntermediate::fold(TIntermAggregate* aggrNode) { if (! areAllChildConst(aggrNode)) return aggrNode; if (aggrNode->isConstructor()) return foldConstructor(aggrNode); TIntermSequence& children = aggrNode->getSequence(); // First, see if this is an operation to constant fold, kick out if not, // see what size the result is if so. bool componentwise = false; // will also say componentwise if a scalar argument gets repeated to make per-component results int objectSize; switch (aggrNode->getOp()) { case EOpAtan: case EOpPow: case EOpMin: case EOpMax: case EOpMix: case EOpClamp: case EOpLessThan: case EOpGreaterThan: case EOpLessThanEqual: case EOpGreaterThanEqual: case EOpVectorEqual: case EOpVectorNotEqual: componentwise = true; objectSize = children[0]->getAsConstantUnion()->getType().computeNumComponents(); break; case EOpCross: case EOpReflect: case EOpRefract: case EOpFaceForward: objectSize = children[0]->getAsConstantUnion()->getType().computeNumComponents(); break; case EOpDistance: case EOpDot: objectSize = 1; break; case EOpOuterProduct: objectSize = children[0]->getAsTyped()->getType().getVectorSize() * children[1]->getAsTyped()->getType().getVectorSize(); break; case EOpStep: componentwise = true; objectSize = std::max(children[0]->getAsTyped()->getType().getVectorSize(), children[1]->getAsTyped()->getType().getVectorSize()); break; case EOpSmoothStep: componentwise = true; objectSize = std::max(children[0]->getAsTyped()->getType().getVectorSize(), children[2]->getAsTyped()->getType().getVectorSize()); break; default: return aggrNode; } TConstUnionArray newConstArray(objectSize); TVector<TConstUnionArray> childConstUnions; for (unsigned int arg = 0; arg < children.size(); ++arg) childConstUnions.push_back(children[arg]->getAsConstantUnion()->getConstArray()); // Second, do the actual folding bool isFloatingPoint = children[0]->getAsTyped()->getBasicType() == EbtFloat || children[0]->getAsTyped()->getBasicType() == EbtDouble; bool isSigned = children[0]->getAsTyped()->getBasicType() == EbtInt; if (componentwise) { for (int comp = 0; comp < objectSize; comp++) { // some arguments are scalars instead of matching vectors; simulate a smear int arg0comp = std::min(comp, children[0]->getAsTyped()->getType().getVectorSize() - 1); int arg1comp = 0; if (children.size() > 1) arg1comp = std::min(comp, children[1]->getAsTyped()->getType().getVectorSize() - 1); int arg2comp = 0; if (children.size() > 2) arg2comp = std::min(comp, children[2]->getAsTyped()->getType().getVectorSize() - 1); switch (aggrNode->getOp()) { case EOpAtan: newConstArray[comp].setDConst(atan2(childConstUnions[0][arg0comp].getDConst(), childConstUnions[1][arg1comp].getDConst())); break; case EOpPow: newConstArray[comp].setDConst(pow(childConstUnions[0][arg0comp].getDConst(), childConstUnions[1][arg1comp].getDConst())); break; case EOpMin: if (isFloatingPoint) newConstArray[comp].setDConst(std::min(childConstUnions[0][arg0comp].getDConst(), childConstUnions[1][arg1comp].getDConst())); else if (isSigned) newConstArray[comp].setIConst(std::min(childConstUnions[0][arg0comp].getIConst(), childConstUnions[1][arg1comp].getIConst())); else newConstArray[comp].setUConst(std::min(childConstUnions[0][arg0comp].getUConst(), childConstUnions[1][arg1comp].getUConst())); break; case EOpMax: if (isFloatingPoint) newConstArray[comp].setDConst(std::max(childConstUnions[0][arg0comp].getDConst(), childConstUnions[1][arg1comp].getDConst())); else if (isSigned) newConstArray[comp].setIConst(std::max(childConstUnions[0][arg0comp].getIConst(), childConstUnions[1][arg1comp].getIConst())); else newConstArray[comp].setUConst(std::max(childConstUnions[0][arg0comp].getUConst(), childConstUnions[1][arg1comp].getUConst())); break; case EOpClamp: if (isFloatingPoint) newConstArray[comp].setDConst(std::min(std::max(childConstUnions[0][arg0comp].getDConst(), childConstUnions[1][arg1comp].getDConst()), childConstUnions[2][arg2comp].getDConst())); else if (isSigned) newConstArray[comp].setIConst(std::min(std::max(childConstUnions[0][arg0comp].getIConst(), childConstUnions[1][arg1comp].getIConst()), childConstUnions[2][arg2comp].getIConst())); else newConstArray[comp].setUConst(std::min(std::max(childConstUnions[0][arg0comp].getUConst(), childConstUnions[1][arg1comp].getUConst()), childConstUnions[2][arg2comp].getUConst())); break; case EOpLessThan: newConstArray[comp].setBConst(childConstUnions[0][arg0comp] < childConstUnions[1][arg1comp]); break; case EOpGreaterThan: newConstArray[comp].setBConst(childConstUnions[0][arg0comp] > childConstUnions[1][arg1comp]); break; case EOpLessThanEqual: newConstArray[comp].setBConst(! (childConstUnions[0][arg0comp] > childConstUnions[1][arg1comp])); break; case EOpGreaterThanEqual: newConstArray[comp].setBConst(! (childConstUnions[0][arg0comp] < childConstUnions[1][arg1comp])); break; case EOpVectorEqual: newConstArray[comp].setBConst(childConstUnions[0][arg0comp] == childConstUnions[1][arg1comp]); break; case EOpVectorNotEqual: newConstArray[comp].setBConst(childConstUnions[0][arg0comp] != childConstUnions[1][arg1comp]); break; case EOpMix: if (children[2]->getAsTyped()->getBasicType() == EbtBool) newConstArray[comp].setDConst(childConstUnions[2][arg2comp].getBConst() ? childConstUnions[1][arg1comp].getDConst() : childConstUnions[0][arg0comp].getDConst()); else newConstArray[comp].setDConst(childConstUnions[0][arg0comp].getDConst() * (1.0 - childConstUnions[2][arg2comp].getDConst()) + childConstUnions[1][arg1comp].getDConst() * childConstUnions[2][arg2comp].getDConst()); break; case EOpStep: newConstArray[comp].setDConst(childConstUnions[1][arg1comp].getDConst() < childConstUnions[0][arg0comp].getDConst() ? 0.0 : 1.0); break; case EOpSmoothStep: { double t = (childConstUnions[2][arg2comp].getDConst() - childConstUnions[0][arg0comp].getDConst()) / (childConstUnions[1][arg1comp].getDConst() - childConstUnions[0][arg0comp].getDConst()); if (t < 0.0) t = 0.0; if (t > 1.0) t = 1.0; newConstArray[comp].setDConst(t * t * (3.0 - 2.0 * t)); break; } default: return aggrNode; } } } else { // Non-componentwise... int numComps = children[0]->getAsConstantUnion()->getType().computeNumComponents(); double dot; switch (aggrNode->getOp()) { case EOpDistance: { double sum = 0.0; for (int comp = 0; comp < numComps; ++comp) { double diff = childConstUnions[1][comp].getDConst() - childConstUnions[0][comp].getDConst(); sum += diff * diff; } newConstArray[0].setDConst(sqrt(sum)); break; } case EOpDot: newConstArray[0].setDConst(childConstUnions[0].dot(childConstUnions[1])); break; case EOpCross: newConstArray[0] = childConstUnions[0][1] * childConstUnions[1][2] - childConstUnions[0][2] * childConstUnions[1][1]; newConstArray[1] = childConstUnions[0][2] * childConstUnions[1][0] - childConstUnions[0][0] * childConstUnions[1][2]; newConstArray[2] = childConstUnions[0][0] * childConstUnions[1][1] - childConstUnions[0][1] * childConstUnions[1][0]; break; case EOpFaceForward: // If dot(Nref, I) < 0 return N, otherwise return –N: Arguments are (N, I, Nref). dot = childConstUnions[1].dot(childConstUnions[2]); for (int comp = 0; comp < numComps; ++comp) { if (dot < 0.0) newConstArray[comp] = childConstUnions[0][comp]; else newConstArray[comp].setDConst(-childConstUnions[0][comp].getDConst()); } break; case EOpReflect: // I – 2 * dot(N, I) * N: Arguments are (I, N). dot = childConstUnions[0].dot(childConstUnions[1]); dot *= 2.0; for (int comp = 0; comp < numComps; ++comp) newConstArray[comp].setDConst(childConstUnions[0][comp].getDConst() - dot * childConstUnions[1][comp].getDConst()); break; case EOpRefract: { // Arguments are (I, N, eta). // k = 1.0 - eta * eta * (1.0 - dot(N, I) * dot(N, I)) // if (k < 0.0) // return dvec(0.0) // else // return eta * I - (eta * dot(N, I) + sqrt(k)) * N dot = childConstUnions[0].dot(childConstUnions[1]); double eta = childConstUnions[2][0].getDConst(); double k = 1.0 - eta * eta * (1.0 - dot * dot); if (k < 0.0) { for (int comp = 0; comp < numComps; ++comp) newConstArray[comp].setDConst(0.0); } else { for (int comp = 0; comp < numComps; ++comp) newConstArray[comp].setDConst(eta * childConstUnions[0][comp].getDConst() - (eta * dot + sqrt(k)) * childConstUnions[1][comp].getDConst()); } break; } case EOpOuterProduct: { int numRows = numComps; int numCols = children[1]->getAsConstantUnion()->getType().computeNumComponents(); for (int row = 0; row < numRows; ++row) for (int col = 0; col < numCols; ++col) newConstArray[col * numRows + row] = childConstUnions[0][row] * childConstUnions[1][col]; break; } default: return aggrNode; } } TIntermConstantUnion *newNode = new TIntermConstantUnion(newConstArray, aggrNode->getType()); newNode->getWritableType().getQualifier().storage = EvqConst; newNode->setLoc(aggrNode->getLoc()); return newNode; }
bool TOutputGLSLBase::visitBinary(Visit visit, TIntermBinary *node) { bool visitChildren = true; TInfoSinkBase &out = objSink(); switch (node->getOp()) { case EOpInitialize: if (visit == InVisit) { out << " = "; // RHS of initialize is not being declared. mDeclaringVariables = false; } break; case EOpAssign: writeTriplet(visit, "(", " = ", ")"); break; case EOpAddAssign: writeTriplet(visit, "(", " += ", ")"); break; case EOpSubAssign: writeTriplet(visit, "(", " -= ", ")"); break; case EOpDivAssign: writeTriplet(visit, "(", " /= ", ")"); break; case EOpIModAssign: writeTriplet(visit, "(", " %= ", ")"); break; // Notice the fall-through. case EOpMulAssign: case EOpVectorTimesMatrixAssign: case EOpVectorTimesScalarAssign: case EOpMatrixTimesScalarAssign: case EOpMatrixTimesMatrixAssign: writeTriplet(visit, "(", " *= ", ")"); break; case EOpBitShiftLeftAssign: writeTriplet(visit, "(", " <<= ", ")"); break; case EOpBitShiftRightAssign: writeTriplet(visit, "(", " >>= ", ")"); break; case EOpBitwiseAndAssign: writeTriplet(visit, "(", " &= ", ")"); break; case EOpBitwiseXorAssign: writeTriplet(visit, "(", " ^= ", ")"); break; case EOpBitwiseOrAssign: writeTriplet(visit, "(", " |= ", ")"); break; case EOpIndexDirect: writeTriplet(visit, NULL, "[", "]"); break; case EOpIndexIndirect: if (node->getAddIndexClamp()) { if (visit == InVisit) { if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC) out << "[int(clamp(float("; else out << "[webgl_int_clamp("; } else if (visit == PostVisit) { int maxSize; TIntermTyped *left = node->getLeft(); TType leftType = left->getType(); if (left->isArray()) { // The shader will fail validation if the array length is not > 0. maxSize = leftType.getArraySize() - 1; } else { maxSize = leftType.getNominalSize() - 1; } if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC) out << "), 0.0, float(" << maxSize << ")))]"; else out << ", 0, " << maxSize << ")]"; } } else { writeTriplet(visit, NULL, "[", "]"); } break; case EOpIndexDirectStruct: if (visit == InVisit) { // Here we are writing out "foo.bar", where "foo" is struct // and "bar" is field. In AST, it is represented as a binary // node, where left child represents "foo" and right child "bar". // The node itself represents ".". The struct field "bar" is // actually stored as an index into TStructure::fields. out << "."; const TStructure *structure = node->getLeft()->getType().getStruct(); const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion(); const TField *field = structure->fields()[index->getIConst(0)]; TString fieldName = field->name(); if (!mSymbolTable.findBuiltIn(structure->name(), mShaderVersion)) fieldName = hashName(fieldName); out << fieldName; visitChildren = false; } break; case EOpIndexDirectInterfaceBlock: if (visit == InVisit) { out << "."; const TInterfaceBlock *interfaceBlock = node->getLeft()->getType().getInterfaceBlock(); const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion(); const TField *field = interfaceBlock->fields()[index->getIConst(0)]; TString fieldName = field->name(); ASSERT(!mSymbolTable.findBuiltIn(interfaceBlock->name(), mShaderVersion)); fieldName = hashName(fieldName); out << fieldName; visitChildren = false; } break; case EOpVectorSwizzle: if (visit == InVisit) { out << "."; TIntermAggregate *rightChild = node->getRight()->getAsAggregate(); TIntermSequence *sequence = rightChild->getSequence(); for (TIntermSequence::iterator sit = sequence->begin(); sit != sequence->end(); ++sit) { TIntermConstantUnion *element = (*sit)->getAsConstantUnion(); ASSERT(element->getBasicType() == EbtInt); ASSERT(element->getNominalSize() == 1); const TConstantUnion& data = element->getUnionArrayPointer()[0]; ASSERT(data.getType() == EbtInt); switch (data.getIConst()) { case 0: out << "x"; break; case 1: out << "y"; break; case 2: out << "z"; break; case 3: out << "w"; break; default: UNREACHABLE(); } } visitChildren = false; } break; case EOpAdd: writeTriplet(visit, "(", " + ", ")"); break; case EOpSub: writeTriplet(visit, "(", " - ", ")"); break; case EOpMul: writeTriplet(visit, "(", " * ", ")"); break; case EOpDiv: writeTriplet(visit, "(", " / ", ")"); break; case EOpIMod: writeTriplet(visit, "(", " % ", ")"); break; case EOpBitShiftLeft: writeTriplet(visit, "(", " << ", ")"); break; case EOpBitShiftRight: writeTriplet(visit, "(", " >> ", ")"); break; case EOpBitwiseAnd: writeTriplet(visit, "(", " & ", ")"); break; case EOpBitwiseXor: writeTriplet(visit, "(", " ^ ", ")"); break; case EOpBitwiseOr: writeTriplet(visit, "(", " | ", ")"); break; case EOpEqual: writeTriplet(visit, "(", " == ", ")"); break; case EOpNotEqual: writeTriplet(visit, "(", " != ", ")"); break; case EOpLessThan: writeTriplet(visit, "(", " < ", ")"); break; case EOpGreaterThan: writeTriplet(visit, "(", " > ", ")"); break; case EOpLessThanEqual: writeTriplet(visit, "(", " <= ", ")"); break; case EOpGreaterThanEqual: writeTriplet(visit, "(", " >= ", ")"); break; // Notice the fall-through. case EOpVectorTimesScalar: case EOpVectorTimesMatrix: case EOpMatrixTimesVector: case EOpMatrixTimesScalar: case EOpMatrixTimesMatrix: writeTriplet(visit, "(", " * ", ")"); break; case EOpLogicalOr: writeTriplet(visit, "(", " || ", ")"); break; case EOpLogicalXor: writeTriplet(visit, "(", " ^^ ", ")"); break; case EOpLogicalAnd: writeTriplet(visit, "(", " && ", ")"); break; default: UNREACHABLE(); } return visitChildren; }
// // Do folding between a pair of nodes // TIntermTyped* TIntermConstantUnion::fold(TOperator op, TIntermTyped* constantNode) { TConstUnion *unionArray = getUnionArrayPointer(); int objectSize = getType().getObjectSize(); TConstUnion* newConstArray = 0; // For most cases, the return type matches the argument type, so set that // up and just code to exceptions below. TType returnType; returnType.shallowCopy(getType()); // // A pair of nodes is to be folded together // TIntermConstantUnion *node = constantNode->getAsConstantUnion(); TConstUnion *rightUnionArray = node->getUnionArrayPointer(); if (constantNode->getType().getObjectSize() == 1 && objectSize > 1) { // for a case like float f = vec4(2,3,4,5) + 1.2; rightUnionArray = new TConstUnion[objectSize]; for (int i = 0; i < objectSize; ++i) rightUnionArray[i] = *node->getUnionArrayPointer(); } else if (constantNode->getType().getObjectSize() > 1 && objectSize == 1) { // for a case like float f = 1.2 + vec4(2,3,4,5); rightUnionArray = node->getUnionArrayPointer(); unionArray = new TConstUnion[constantNode->getType().getObjectSize()]; for (int i = 0; i < constantNode->getType().getObjectSize(); ++i) unionArray[i] = *getUnionArrayPointer(); returnType.shallowCopy(node->getType()); objectSize = constantNode->getType().getObjectSize(); } int index = 0; bool boolNodeFlag = false; switch(op) { case EOpAdd: newConstArray = new TConstUnion[objectSize]; for (int i = 0; i < objectSize; i++) newConstArray[i] = unionArray[i] + rightUnionArray[i]; break; case EOpSub: newConstArray = new TConstUnion[objectSize]; for (int i = 0; i < objectSize; i++) newConstArray[i] = unionArray[i] - rightUnionArray[i]; break; case EOpMul: case EOpVectorTimesScalar: case EOpMatrixTimesScalar: newConstArray = new TConstUnion[objectSize]; for (int i = 0; i < objectSize; i++) newConstArray[i] = unionArray[i] * rightUnionArray[i]; break; case EOpMatrixTimesMatrix: newConstArray = new TConstUnion[getMatrixRows() * node->getMatrixCols()]; for (int row = 0; row < getMatrixRows(); row++) { for (int column = 0; column < node->getMatrixCols(); column++) { double sum = 0.0f; for (int i = 0; i < node->getMatrixRows(); i++) sum += unionArray[i * getMatrixRows() + row].getDConst() * rightUnionArray[column * node->getMatrixRows() + i].getDConst(); newConstArray[column * getMatrixRows() + row].setDConst(sum); } } returnType.shallowCopy(TType(getType().getBasicType(), EvqConst, 0, getMatrixRows(), node->getMatrixCols())); break; case EOpDiv: newConstArray = new TConstUnion[objectSize]; for (int i = 0; i < objectSize; i++) { switch (getType().getBasicType()) { case EbtDouble: case EbtFloat: newConstArray[i].setDConst(unionArray[i].getDConst() / rightUnionArray[i].getDConst()); break; case EbtInt: if (rightUnionArray[i] == 0) { newConstArray[i].setIConst(0xEFFFFFFF); } else newConstArray[i].setIConst(unionArray[i].getIConst() / rightUnionArray[i].getIConst()); break; case EbtUint: if (rightUnionArray[i] == 0) { newConstArray[i].setUConst(0xFFFFFFFF); } else newConstArray[i].setUConst(unionArray[i].getUConst() / rightUnionArray[i].getUConst()); break; default: return 0; } } break; case EOpMatrixTimesVector: newConstArray = new TConstUnion[getMatrixRows()]; for (int i = 0; i < getMatrixRows(); i++) { double sum = 0.0f; for (int j = 0; j < node->getVectorSize(); j++) { sum += unionArray[j*getMatrixRows() + i].getDConst() * rightUnionArray[j].getDConst(); } newConstArray[i].setDConst(sum); } returnType.shallowCopy(TType(getBasicType(), EvqConst, getMatrixRows())); break; case EOpVectorTimesMatrix: newConstArray = new TConstUnion[node->getMatrixCols()]; for (int i = 0; i < node->getMatrixCols(); i++) { double sum = 0.0f; for (int j = 0; j < getVectorSize(); j++) sum += unionArray[j].getDConst() * rightUnionArray[i*node->getMatrixRows() + j].getDConst(); newConstArray[i].setDConst(sum); } returnType.shallowCopy(TType(getBasicType(), EvqConst, node->getMatrixCols())); break; case EOpMod: newConstArray = new TConstUnion[objectSize]; for (int i = 0; i < objectSize; i++) newConstArray[i] = unionArray[i] % rightUnionArray[i]; break; case EOpRightShift: newConstArray = new TConstUnion[objectSize]; for (int i = 0; i < objectSize; i++) newConstArray[i] = unionArray[i] >> rightUnionArray[i]; break; case EOpLeftShift: newConstArray = new TConstUnion[objectSize]; for (int i = 0; i < objectSize; i++) newConstArray[i] = unionArray[i] << rightUnionArray[i]; break; case EOpAnd: newConstArray = new TConstUnion[objectSize]; for (int i = 0; i < objectSize; i++) newConstArray[i] = unionArray[i] & rightUnionArray[i]; break; case EOpInclusiveOr: newConstArray = new TConstUnion[objectSize]; for (int i = 0; i < objectSize; i++) newConstArray[i] = unionArray[i] | rightUnionArray[i]; break; case EOpExclusiveOr: newConstArray = new TConstUnion[objectSize]; for (int i = 0; i < objectSize; i++) newConstArray[i] = unionArray[i] ^ rightUnionArray[i]; break; case EOpLogicalAnd: // this code is written for possible future use, will not get executed currently newConstArray = new TConstUnion[objectSize]; for (int i = 0; i < objectSize; i++) newConstArray[i] = unionArray[i] && rightUnionArray[i]; break; case EOpLogicalOr: // this code is written for possible future use, will not get executed currently newConstArray = new TConstUnion[objectSize]; for (int i = 0; i < objectSize; i++) newConstArray[i] = unionArray[i] || rightUnionArray[i]; break; case EOpLogicalXor: newConstArray = new TConstUnion[objectSize]; for (int i = 0; i < objectSize; i++) { switch (getType().getBasicType()) { case EbtBool: newConstArray[i].setBConst((unionArray[i] == rightUnionArray[i]) ? false : true); break; default: assert(false && "Default missing"); } } break; case EOpLessThan: assert(objectSize == 1); newConstArray = new TConstUnion[1]; newConstArray->setBConst(*unionArray < *rightUnionArray); returnType.shallowCopy(TType(EbtBool, EvqConst)); break; case EOpGreaterThan: assert(objectSize == 1); newConstArray = new TConstUnion[1]; newConstArray->setBConst(*unionArray > *rightUnionArray); returnType.shallowCopy(TType(EbtBool, EvqConst)); break; case EOpLessThanEqual: { assert(objectSize == 1); TConstUnion constant; constant.setBConst(*unionArray > *rightUnionArray); newConstArray = new TConstUnion[1]; newConstArray->setBConst(!constant.getBConst()); returnType.shallowCopy(TType(EbtBool, EvqConst)); break; } case EOpGreaterThanEqual: { assert(objectSize == 1); TConstUnion constant; constant.setBConst(*unionArray < *rightUnionArray); newConstArray = new TConstUnion[1]; newConstArray->setBConst(!constant.getBConst()); returnType.shallowCopy(TType(EbtBool, EvqConst)); break; } case EOpEqual: if (getType().getBasicType() == EbtStruct) { if (! CompareStructure(node->getType(), node->getUnionArrayPointer(), unionArray)) boolNodeFlag = true; } else { for (int i = 0; i < objectSize; i++) { if (unionArray[i] != rightUnionArray[i]) { boolNodeFlag = true; break; // break out of for loop } } } newConstArray = new TConstUnion[1]; newConstArray->setBConst(! boolNodeFlag); returnType.shallowCopy(TType(EbtBool, EvqConst)); break; case EOpNotEqual: if (getType().getBasicType() == EbtStruct) { if (CompareStructure(node->getType(), node->getUnionArrayPointer(), unionArray)) boolNodeFlag = true; } else { for (int i = 0; i < objectSize; i++) { if (unionArray[i] == rightUnionArray[i]) { boolNodeFlag = true; break; // break out of for loop } } } newConstArray = new TConstUnion[1]; newConstArray->setBConst(! boolNodeFlag); returnType.shallowCopy(TType(EbtBool, EvqConst)); break; default: return 0; } TIntermConstantUnion *newNode = new TIntermConstantUnion(newConstArray, returnType); newNode->setLoc(getLoc()); return newNode; }
// // The fold functions see if an operation on a constant can be done in place, // without generating run-time code. // // Returns the node to keep using, which may or may not be the node passed in. // TIntermTyped *TIntermConstantUnion::fold( TOperator op, TIntermTyped *constantNode, TInfoSink &infoSink) { ConstantUnion *unionArray = getUnionArrayPointer(); if (!unionArray) return NULL; size_t objectSize = getType().getObjectSize(); if (constantNode) { // binary operations TIntermConstantUnion *node = constantNode->getAsConstantUnion(); ConstantUnion *rightUnionArray = node->getUnionArrayPointer(); TType returnType = getType(); if (!rightUnionArray) return NULL; // for a case like float f = 1.2 + vec4(2,3,4,5); if (constantNode->getType().getObjectSize() == 1 && objectSize > 1) { rightUnionArray = new ConstantUnion[objectSize]; for (size_t i = 0; i < objectSize; ++i) { rightUnionArray[i] = *node->getUnionArrayPointer(); } returnType = getType(); } else if (constantNode->getType().getObjectSize() > 1 && objectSize == 1) { // for a case like float f = vec4(2,3,4,5) + 1.2; unionArray = new ConstantUnion[constantNode->getType().getObjectSize()]; for (size_t i = 0; i < constantNode->getType().getObjectSize(); ++i) { unionArray[i] = *getUnionArrayPointer(); } returnType = node->getType(); objectSize = constantNode->getType().getObjectSize(); } ConstantUnion *tempConstArray = NULL; TIntermConstantUnion *tempNode; bool boolNodeFlag = false; switch(op) { case EOpAdd: tempConstArray = new ConstantUnion[objectSize]; for (size_t i = 0; i < objectSize; i++) tempConstArray[i] = unionArray[i] + rightUnionArray[i]; break; case EOpSub: tempConstArray = new ConstantUnion[objectSize]; for (size_t i = 0; i < objectSize; i++) tempConstArray[i] = unionArray[i] - rightUnionArray[i]; break; case EOpMul: case EOpVectorTimesScalar: case EOpMatrixTimesScalar: tempConstArray = new ConstantUnion[objectSize]; for (size_t i = 0; i < objectSize; i++) tempConstArray[i] = unionArray[i] * rightUnionArray[i]; break; case EOpMatrixTimesMatrix: { if (getType().getBasicType() != EbtFloat || node->getBasicType() != EbtFloat) { infoSink.info.message( EPrefixInternalError, getLine(), "Constant Folding cannot be done for matrix multiply"); return NULL; } const int leftCols = getCols(); const int leftRows = getRows(); const int rightCols = constantNode->getType().getCols(); const int rightRows = constantNode->getType().getRows(); const int resultCols = rightCols; const int resultRows = leftRows; tempConstArray = new ConstantUnion[resultCols*resultRows]; for (int row = 0; row < resultRows; row++) { for (int column = 0; column < resultCols; column++) { tempConstArray[resultRows * column + row].setFConst(0.0f); for (int i = 0; i < leftCols; i++) { tempConstArray[resultRows * column + row].setFConst( tempConstArray[resultRows * column + row].getFConst() + unionArray[i * leftRows + row].getFConst() * rightUnionArray[column * rightRows + i].getFConst()); } } } // update return type for matrix product returnType.setPrimarySize(resultCols); returnType.setSecondarySize(resultRows); } break; case EOpDiv: { tempConstArray = new ConstantUnion[objectSize]; for (size_t i = 0; i < objectSize; i++) { switch (getType().getBasicType()) { case EbtFloat: if (rightUnionArray[i] == 0.0f) { infoSink.info.message( EPrefixWarning, getLine(), "Divide by zero error during constant folding"); tempConstArray[i].setFConst( unionArray[i].getFConst() < 0 ? -FLT_MAX : FLT_MAX); } else { tempConstArray[i].setFConst( unionArray[i].getFConst() / rightUnionArray[i].getFConst()); } break; case EbtInt: if (rightUnionArray[i] == 0) { infoSink.info.message( EPrefixWarning, getLine(), "Divide by zero error during constant folding"); tempConstArray[i].setIConst(INT_MAX); } else { tempConstArray[i].setIConst( unionArray[i].getIConst() / rightUnionArray[i].getIConst()); } break; case EbtUInt: if (rightUnionArray[i] == 0) { infoSink.info.message( EPrefixWarning, getLine(), "Divide by zero error during constant folding"); tempConstArray[i].setUConst(UINT_MAX); } else { tempConstArray[i].setUConst( unionArray[i].getUConst() / rightUnionArray[i].getUConst()); } break; default: infoSink.info.message( EPrefixInternalError, getLine(), "Constant folding cannot be done for \"/\""); return NULL; } } } break; case EOpMatrixTimesVector: { if (node->getBasicType() != EbtFloat) { infoSink.info.message( EPrefixInternalError, getLine(), "Constant Folding cannot be done for matrix times vector"); return NULL; } const int matrixCols = getCols(); const int matrixRows = getRows(); tempConstArray = new ConstantUnion[matrixRows]; for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++) { tempConstArray[matrixRow].setFConst(0.0f); for (int col = 0; col < matrixCols; col++) { tempConstArray[matrixRow].setFConst( tempConstArray[matrixRow].getFConst() + unionArray[col * matrixRows + matrixRow].getFConst() * rightUnionArray[col].getFConst()); } } returnType = node->getType(); returnType.setPrimarySize(matrixRows); tempNode = new TIntermConstantUnion(tempConstArray, returnType); tempNode->setLine(getLine()); return tempNode; } case EOpVectorTimesMatrix: { if (getType().getBasicType() != EbtFloat) { infoSink.info.message( EPrefixInternalError, getLine(), "Constant Folding cannot be done for vector times matrix"); return NULL; } const int matrixCols = constantNode->getType().getCols(); const int matrixRows = constantNode->getType().getRows(); tempConstArray = new ConstantUnion[matrixCols]; for (int matrixCol = 0; matrixCol < matrixCols; matrixCol++) { tempConstArray[matrixCol].setFConst(0.0f); for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++) { tempConstArray[matrixCol].setFConst( tempConstArray[matrixCol].getFConst() + unionArray[matrixRow].getFConst() * rightUnionArray[matrixCol * matrixRows + matrixRow].getFConst()); } } returnType.setPrimarySize(matrixCols); } break; case EOpLogicalAnd: // this code is written for possible future use, // will not get executed currently { tempConstArray = new ConstantUnion[objectSize]; for (size_t i = 0; i < objectSize; i++) { tempConstArray[i] = unionArray[i] && rightUnionArray[i]; } } break; case EOpLogicalOr: // this code is written for possible future use, // will not get executed currently { tempConstArray = new ConstantUnion[objectSize]; for (size_t i = 0; i < objectSize; i++) { tempConstArray[i] = unionArray[i] || rightUnionArray[i]; } } break; case EOpLogicalXor: { tempConstArray = new ConstantUnion[objectSize]; for (size_t i = 0; i < objectSize; i++) { switch (getType().getBasicType()) { case EbtBool: tempConstArray[i].setBConst( unionArray[i] == rightUnionArray[i] ? false : true); break; default: UNREACHABLE(); break; } } } break; case EOpLessThan: ASSERT(objectSize == 1); tempConstArray = new ConstantUnion[1]; tempConstArray->setBConst(*unionArray < *rightUnionArray); returnType = TType(EbtBool, EbpUndefined, EvqConst); break; case EOpGreaterThan: ASSERT(objectSize == 1); tempConstArray = new ConstantUnion[1]; tempConstArray->setBConst(*unionArray > *rightUnionArray); returnType = TType(EbtBool, EbpUndefined, EvqConst); break; case EOpLessThanEqual: { ASSERT(objectSize == 1); ConstantUnion constant; constant.setBConst(*unionArray > *rightUnionArray); tempConstArray = new ConstantUnion[1]; tempConstArray->setBConst(!constant.getBConst()); returnType = TType(EbtBool, EbpUndefined, EvqConst); break; } case EOpGreaterThanEqual: { ASSERT(objectSize == 1); ConstantUnion constant; constant.setBConst(*unionArray < *rightUnionArray); tempConstArray = new ConstantUnion[1]; tempConstArray->setBConst(!constant.getBConst()); returnType = TType(EbtBool, EbpUndefined, EvqConst); break; } case EOpEqual: if (getType().getBasicType() == EbtStruct) { if (!CompareStructure(node->getType(), node->getUnionArrayPointer(), unionArray)) { boolNodeFlag = true; } } else { for (size_t i = 0; i < objectSize; i++) { if (unionArray[i] != rightUnionArray[i]) { boolNodeFlag = true; break; // break out of for loop } } } tempConstArray = new ConstantUnion[1]; if (!boolNodeFlag) { tempConstArray->setBConst(true); } else { tempConstArray->setBConst(false); } tempNode = new TIntermConstantUnion( tempConstArray, TType(EbtBool, EbpUndefined, EvqConst)); tempNode->setLine(getLine()); return tempNode; case EOpNotEqual: if (getType().getBasicType() == EbtStruct) { if (CompareStructure(node->getType(), node->getUnionArrayPointer(), unionArray)) { boolNodeFlag = true; } } else { for (size_t i = 0; i < objectSize; i++) { if (unionArray[i] == rightUnionArray[i]) { boolNodeFlag = true; break; // break out of for loop } } } tempConstArray = new ConstantUnion[1]; if (!boolNodeFlag) { tempConstArray->setBConst(true); } else { tempConstArray->setBConst(false); } tempNode = new TIntermConstantUnion( tempConstArray, TType(EbtBool, EbpUndefined, EvqConst)); tempNode->setLine(getLine()); return tempNode; default: infoSink.info.message( EPrefixInternalError, getLine(), "Invalid operator for constant folding"); return NULL; } tempNode = new TIntermConstantUnion(tempConstArray, returnType); tempNode->setLine(getLine()); return tempNode; } else { // // Do unary operations // TIntermConstantUnion *newNode = 0; ConstantUnion* tempConstArray = new ConstantUnion[objectSize]; for (size_t i = 0; i < objectSize; i++) { switch(op) { case EOpNegative: switch (getType().getBasicType()) { case EbtFloat: tempConstArray[i].setFConst(-unionArray[i].getFConst()); break; case EbtInt: tempConstArray[i].setIConst(-unionArray[i].getIConst()); break; case EbtUInt: tempConstArray[i].setUConst(static_cast<unsigned int>( -static_cast<int>(unionArray[i].getUConst()))); break; default: infoSink.info.message( EPrefixInternalError, getLine(), "Unary operation not folded into constant"); return NULL; } break; case EOpPositive: switch (getType().getBasicType()) { case EbtFloat: tempConstArray[i].setFConst(unionArray[i].getFConst()); break; case EbtInt: tempConstArray[i].setIConst(unionArray[i].getIConst()); break; case EbtUInt: tempConstArray[i].setUConst(static_cast<unsigned int>( static_cast<int>(unionArray[i].getUConst()))); break; default: infoSink.info.message( EPrefixInternalError, getLine(), "Unary operation not folded into constant"); return NULL; } break; case EOpLogicalNot: // this code is written for possible future use, // will not get executed currently switch (getType().getBasicType()) { case EbtBool: tempConstArray[i].setBConst(!unionArray[i].getBConst()); break; default: infoSink.info.message( EPrefixInternalError, getLine(), "Unary operation not folded into constant"); return NULL; } break; default: return NULL; } } newNode = new TIntermConstantUnion(tempConstArray, getType()); newNode->setLine(getLine()); return newNode; } }
// // Do constant folding for an aggregate node that has all its children // as constants and an operator that requires constant folding. // TIntermTyped* TIntermediate::fold(TIntermAggregate* aggrNode) { if (! areAllChildConst(aggrNode)) return aggrNode; if (aggrNode->isConstructor()) return foldConstructor(aggrNode); TIntermSequence& children = aggrNode->getSequence(); // First, see if this is an operation to constant fold, kick out if not, // see what size the result is if so. bool componentwise = false; // will also say componentwise if a scalar argument gets repeated to make per-component results int objectSize; switch (aggrNode->getOp()) { case EOpAtan: case EOpPow: case EOpMin: case EOpMax: case EOpMix: case EOpClamp: componentwise = true; objectSize = children[0]->getAsConstantUnion()->getType().getObjectSize(); break; case EOpCross: case EOpReflect: case EOpRefract: case EOpFaceForward: objectSize = children[0]->getAsConstantUnion()->getType().getObjectSize(); break; case EOpDistance: case EOpDot: objectSize = 1; break; case EOpOuterProduct: objectSize = children[0]->getAsTyped()->getType().getVectorSize() * children[1]->getAsTyped()->getType().getVectorSize(); break; case EOpStep: componentwise = true; objectSize = std::max(children[0]->getAsTyped()->getType().getVectorSize(), children[1]->getAsTyped()->getType().getVectorSize()); break; case EOpSmoothStep: componentwise = true; objectSize = std::max(children[0]->getAsTyped()->getType().getVectorSize(), children[2]->getAsTyped()->getType().getVectorSize()); break; default: return aggrNode; } TConstUnion* newConstArray = new TConstUnion[objectSize]; TVector<TConstUnion*> childConstUnions; for (unsigned int arg = 0; arg < children.size(); ++arg) childConstUnions.push_back(children[arg]->getAsConstantUnion()->getUnionArrayPointer()); // Second, do the actual folding bool isFloatingPoint = children[0]->getAsTyped()->getBasicType() == EbtFloat || children[0]->getAsTyped()->getBasicType() == EbtDouble; bool isSigned = children[0]->getAsTyped()->getBasicType() == EbtInt; if (componentwise) { for (int comp = 0; comp < objectSize; comp++) { // some arguments are scalars instead of matching vectors; simulate a smear int arg0comp = std::min(comp, children[0]->getAsTyped()->getType().getVectorSize() - 1); int arg1comp; if (children.size() > 1) arg1comp = std::min(comp, children[1]->getAsTyped()->getType().getVectorSize() - 1); int arg2comp; if (children.size() > 2) arg2comp = std::min(comp, children[2]->getAsTyped()->getType().getVectorSize() - 1); switch (aggrNode->getOp()) { case EOpAtan: newConstArray[comp].setDConst(atan2(childConstUnions[0][arg0comp].getDConst(), childConstUnions[1][arg1comp].getDConst())); break; case EOpPow: newConstArray[comp].setDConst(pow(childConstUnions[0][arg0comp].getDConst(), childConstUnions[1][arg1comp].getDConst())); break; case EOpMin: if (isFloatingPoint) newConstArray[comp].setDConst(std::min(childConstUnions[0][arg0comp].getDConst(), childConstUnions[1][arg1comp].getDConst())); else if (isSigned) newConstArray[comp].setIConst(std::min(childConstUnions[0][arg0comp].getIConst(), childConstUnions[1][arg1comp].getIConst())); else newConstArray[comp].setUConst(std::min(childConstUnions[0][arg0comp].getUConst(), childConstUnions[1][arg1comp].getUConst())); break; case EOpMax: if (isFloatingPoint) newConstArray[comp].setDConst(std::max(childConstUnions[0][arg0comp].getDConst(), childConstUnions[1][arg1comp].getDConst())); else if (isSigned) newConstArray[comp].setIConst(std::max(childConstUnions[0][arg0comp].getIConst(), childConstUnions[1][arg1comp].getIConst())); else newConstArray[comp].setUConst(std::max(childConstUnions[0][arg0comp].getUConst(), childConstUnions[1][arg1comp].getUConst())); break; case EOpClamp: if (isFloatingPoint) newConstArray[comp].setDConst(std::min(std::max(childConstUnions[0][arg0comp].getDConst(), childConstUnions[1][arg1comp].getDConst()), childConstUnions[2][arg2comp].getDConst())); else if (isSigned) newConstArray[comp].setIConst(std::min(std::max(childConstUnions[0][arg0comp].getIConst(), childConstUnions[1][arg1comp].getIConst()), childConstUnions[2][arg2comp].getIConst())); else newConstArray[comp].setUConst(std::min(std::max(childConstUnions[0][arg0comp].getUConst(), childConstUnions[1][arg1comp].getUConst()), childConstUnions[2][arg2comp].getUConst())); break; case EOpMix: if (children[2]->getAsTyped()->getBasicType() == EbtBool) newConstArray[comp].setDConst(childConstUnions[2][arg2comp].getBConst() ? childConstUnions[1][arg1comp].getDConst() : childConstUnions[0][arg0comp].getDConst()); else newConstArray[comp].setDConst(childConstUnions[0][arg0comp].getDConst() * (1.0 - childConstUnions[2][arg2comp].getDConst()) + childConstUnions[1][arg1comp].getDConst() * childConstUnions[2][arg2comp].getDConst()); break; case EOpStep: newConstArray[comp].setDConst(childConstUnions[1][arg1comp].getDConst() < childConstUnions[0][arg0comp].getDConst() ? 0.0 : 1.0); break; case EOpSmoothStep: { double t = (childConstUnions[2][arg2comp].getDConst() - childConstUnions[0][arg0comp].getDConst()) / (childConstUnions[1][arg1comp].getDConst() - childConstUnions[0][arg0comp].getDConst()); if (t < 0.0) t = 0.0; if (t > 1.0) t = 1.0; newConstArray[comp].setDConst(t * t * (3.0 - 2.0 * t)); break; } default: return aggrNode; } } } else { // Non-componentwise... switch (aggrNode->getOp()) { // TODO: Functionality: constant folding: the rest of the ops have to be fleshed out case EOpModf: case EOpDistance: case EOpDot: case EOpCross: case EOpFaceForward: case EOpReflect: case EOpRefract: case EOpOuterProduct: return aggrNode; default: return aggrNode; } } TIntermConstantUnion *newNode = new TIntermConstantUnion(newConstArray, aggrNode->getType()); newNode->getWritableType().getQualifier().storage = EvqConst; newNode->setLoc(aggrNode->getLoc()); return newNode; }
// // Do single unary node folding // TIntermTyped* TIntermConstantUnion::fold(TOperator op, const TType& returnType) { TConstUnion *unionArray = getUnionArrayPointer(); int objectSize = getType().getObjectSize(); // First, size the result, which is mostly the same as the argument's size, // but not always. TConstUnion* newConstArray; switch (op) { // TODO: functionality: constant folding: finish listing exceptions to size here case EOpDeterminant: case EOpAny: case EOpAll: case EOpLength: newConstArray = new TConstUnion[1]; break; case EOpEmitStreamVertex: case EOpEndStreamPrimitive: // These don't actually fold return 0; default: newConstArray = new TConstUnion[objectSize]; } // Process non-component-wise operations switch (op) { case EOpLength: case EOpNormalize: { double sum = 0; for (int i = 0; i < objectSize; i++) sum += double(unionArray[i].getDConst()) * unionArray[i].getDConst(); double length = sqrt(sum); if (op == EOpLength) newConstArray[0].setDConst(length); else { for (int i = 0; i < objectSize; i++) newConstArray[i].setDConst(unionArray[i].getDConst() / length); } break; } default: break; } for (int i = 0; i < objectSize; i++) { switch (op) { case EOpNegative: switch (getType().getBasicType()) { case EbtDouble: case EbtFloat: newConstArray[i].setDConst(-unionArray[i].getDConst()); break; case EbtInt: newConstArray[i].setIConst(-unionArray[i].getIConst()); break; case EbtUint: newConstArray[i].setUConst(static_cast<unsigned int>(-static_cast<int>(unionArray[i].getUConst()))); break; default: return 0; } break; case EOpLogicalNot: case EOpVectorLogicalNot: switch (getType().getBasicType()) { case EbtBool: newConstArray[i].setBConst(!unionArray[i].getBConst()); break; default: return 0; } break; case EOpBitwiseNot: newConstArray[i] = ~unionArray[i]; break; case EOpRadians: newConstArray[i].setDConst(unionArray[i].getDConst() * pi / 180.0); break; case EOpDegrees: newConstArray[i].setDConst(unionArray[i].getDConst() * 180.0 / pi); break; case EOpSin: newConstArray[i].setDConst(sin(unionArray[i].getDConst())); break; case EOpCos: newConstArray[i].setDConst(cos(unionArray[i].getDConst())); break; case EOpTan: newConstArray[i].setDConst(tan(unionArray[i].getDConst())); break; case EOpAsin: newConstArray[i].setDConst(asin(unionArray[i].getDConst())); break; case EOpAcos: newConstArray[i].setDConst(acos(unionArray[i].getDConst())); break; case EOpAtan: newConstArray[i].setDConst(atan(unionArray[i].getDConst())); break; case EOpLength: case EOpNormalize: // handled above as special case break; case EOpDPdx: case EOpDPdy: case EOpFwidth: // The derivatives are all mandated to create a constant 0. newConstArray[i].setDConst(0.0); break; case EOpExp: newConstArray[i].setDConst(exp(unionArray[i].getDConst())); break; case EOpLog: newConstArray[i].setDConst(log(unionArray[i].getDConst())); break; case EOpExp2: { const double inv_log2_e = 0.69314718055994530941723212145818; newConstArray[i].setDConst(exp(unionArray[i].getDConst() * inv_log2_e)); break; } case EOpLog2: { const double log2_e = 1.4426950408889634073599246810019; newConstArray[i].setDConst(log2_e * log(unionArray[i].getDConst())); break; } case EOpSqrt: newConstArray[i].setDConst(sqrt(unionArray[i].getDConst())); break; case EOpInverseSqrt: newConstArray[i].setDConst(1.0 / sqrt(unionArray[i].getDConst())); break; case EOpAbs: if (unionArray[i].getType() == EbtDouble) newConstArray[i].setDConst(fabs(unionArray[i].getDConst())); else if (unionArray[i].getType() == EbtInt) newConstArray[i].setIConst(abs(unionArray[i].getIConst())); else newConstArray[i] = unionArray[i]; break; case EOpSign: #define SIGN(X) (X == 0 ? 0 : (X < 0 ? -1 : 1)) if (unionArray[i].getType() == EbtDouble) newConstArray[i].setDConst(SIGN(unionArray[i].getDConst())); else newConstArray[i].setIConst(SIGN(unionArray[i].getIConst())); break; case EOpFloor: newConstArray[i].setDConst(floor(unionArray[i].getDConst())); break; case EOpTrunc: if (unionArray[i].getDConst() > 0) newConstArray[i].setDConst(floor(unionArray[i].getDConst())); else newConstArray[i].setDConst(ceil(unionArray[i].getDConst())); break; case EOpRound: newConstArray[i].setDConst(floor(0.5 + unionArray[i].getDConst())); break; case EOpRoundEven: { double flr = floor(unionArray[i].getDConst()); bool even = flr / 2.0 == floor(flr / 2.0); double rounded = even ? ceil(unionArray[i].getDConst() - 0.5) : floor(unionArray[i].getDConst() + 0.5); newConstArray[i].setDConst(rounded); break; } case EOpCeil: newConstArray[i].setDConst(ceil(unionArray[i].getDConst())); break; case EOpFract: { double x = unionArray[i].getDConst(); newConstArray[i].setDConst(x - floor(x)); break; } case EOpIsNan: { newConstArray[i].setBConst(isNan(unionArray[i].getDConst())); break; } case EOpIsInf: { newConstArray[i].setBConst(isInf(unionArray[i].getDConst())); break; } // TODO: Functionality: constant folding: the rest of the ops have to be fleshed out case EOpSinh: case EOpCosh: case EOpTanh: case EOpAsinh: case EOpAcosh: case EOpAtanh: case EOpFloatBitsToInt: case EOpFloatBitsToUint: case EOpIntBitsToFloat: case EOpUintBitsToFloat: case EOpPackSnorm2x16: case EOpUnpackSnorm2x16: case EOpPackUnorm2x16: case EOpUnpackUnorm2x16: case EOpPackHalf2x16: case EOpUnpackHalf2x16: case EOpDeterminant: case EOpMatrixInverse: case EOpTranspose: case EOpAny: case EOpAll: default: return 0; } } TIntermConstantUnion *newNode = new TIntermConstantUnion(newConstArray, returnType); newNode->getWritableType().getQualifier().storage = EvqConst; newNode->setLoc(getLoc()); return newNode; }
bool TOutputGLSLBase::visitBinary(Visit visit, TIntermBinary* node) { bool visitChildren = true; TInfoSinkBase& out = objSink(); switch (node->getOp()) { case EOpInitialize: if (visit == InVisit) { out << " = "; // RHS of initialize is not being declared. mDeclaringVariables = false; } break; case EOpAssign: writeTriplet(visit, "(", " = ", ")"); break; case EOpAddAssign: writeTriplet(visit, "(", " += ", ")"); break; case EOpSubAssign: writeTriplet(visit, "(", " -= ", ")"); break; case EOpDivAssign: writeTriplet(visit, "(", " /= ", ")"); break; // Notice the fall-through. case EOpMulAssign: case EOpVectorTimesMatrixAssign: case EOpVectorTimesScalarAssign: case EOpMatrixTimesScalarAssign: case EOpMatrixTimesMatrixAssign: writeTriplet(visit, "(", " *= ", ")"); break; case EOpIndexDirect: case EOpIndexIndirect: writeTriplet(visit, NULL, "[", "]"); break; case EOpIndexDirectStruct: if (visit == InVisit) { out << "."; // TODO(alokp): ASSERT out << node->getType().getFieldName(); visitChildren = false; } break; case EOpVectorSwizzle: if (visit == InVisit) { out << "."; TIntermAggregate* rightChild = node->getRight()->getAsAggregate(); TIntermSequence& sequence = rightChild->getSequence(); for (TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); ++sit) { TIntermConstantUnion* element = (*sit)->getAsConstantUnion(); ASSERT(element->getBasicType() == EbtInt); ASSERT(element->getNominalSize() == 1); const ConstantUnion& data = element->getUnionArrayPointer()[0]; ASSERT(data.getType() == EbtInt); switch (data.getIConst()) { case 0: out << "x"; break; case 1: out << "y"; break; case 2: out << "z"; break; case 3: out << "w"; break; default: UNREACHABLE(); break; } } visitChildren = false; } break; case EOpAdd: writeTriplet(visit, "(", " + ", ")"); break; case EOpSub: writeTriplet(visit, "(", " - ", ")"); break; case EOpMul: writeTriplet(visit, "(", " * ", ")"); break; case EOpDiv: writeTriplet(visit, "(", " / ", ")"); break; case EOpMod: UNIMPLEMENTED(); break; case EOpEqual: writeTriplet(visit, "(", " == ", ")"); break; case EOpNotEqual: writeTriplet(visit, "(", " != ", ")"); break; case EOpLessThan: writeTriplet(visit, "(", " < ", ")"); break; case EOpGreaterThan: writeTriplet(visit, "(", " > ", ")"); break; case EOpLessThanEqual: writeTriplet(visit, "(", " <= ", ")"); break; case EOpGreaterThanEqual: writeTriplet(visit, "(", " >= ", ")"); break; // Notice the fall-through. case EOpVectorTimesScalar: case EOpVectorTimesMatrix: case EOpMatrixTimesVector: case EOpMatrixTimesScalar: case EOpMatrixTimesMatrix: writeTriplet(visit, "(", " * ", ")"); break; case EOpLogicalOr: writeTriplet(visit, "(", " || ", ")"); break; case EOpLogicalXor: writeTriplet(visit, "(", " ^^ ", ")"); break; case EOpLogicalAnd: writeTriplet(visit, "(", " && ", ")"); break; default: UNREACHABLE(); break; } return visitChildren; }
ParsedValue Parser::parseValue(TIntermTyped* e) { auto binary = e->getAsBinaryNode(); auto symbol = e->getAsSymbolNode(); auto aggregate = e->getAsAggregate(); TIntermConstantUnion* constunion = e->getAsConstantUnion(); if (binary != nullptr) { CodeOp op; switch (binary->getOp()) { case EOpAdd: op = CAdd; break; case EOpSub: op = CSub; break; case EOpMul: op = CMul; break; case EOpDiv: op = CDiv; break; case EOpLessThan: op = CLt; break; case EOpGreaterThan: op = CGt; break; case EOpLessThanEqual: op = CLte; break; case EOpGreaterThanEqual: op = CGte; break; case EOpEqual: op = CEq; break; case EOpNotEqual: op = CNeq; break; case EOpLogicalOr: op = COr; break; case EOpLogicalAnd: op = COr; break; case EOpMatrixTimesVector: op = CMul; break; case EOpVectorSwizzle: { auto field = new PField; field->e = parseValue(binary->getLeft()); for (unsigned i = 0; i < binary->getRight()->getAsAggregate()->getSequence().size(); ++i) { int num = binary->getRight()->getAsAggregate()->getSequence()[i]->getAsConstantUnion()->getUnionArrayPointer()->getIConst(); switch (num) { case 0: field->field += "x"; break; case 1: field->field += "y"; break; case 2: field->field += "z"; break; case 3: field->field += "w"; break; } } ParsedValue value; value.v = field; value.p = binary->getLine().first_line; return value; } //case OpMod: CMod; //case OpInterval: CInterval; default: error("Unsupported operation", e->getLine().first_line); } ParsedValue value; value.v = new POp(op, parseValue(binary->getLeft()), parseValue(binary->getRight())); value.p = e->getLine().first_line; return value; } else if (symbol != nullptr) { ParsedValue value; auto var = new PVar; var->v = symbol->getSymbol().c_str(); value.v = var; value.p = e->getLine().first_line; return value; } else if (constunion != nullptr) { ParsedValue value; value.p = constunion->getLine().first_line; auto constVar = new PConst; switch (constunion->getType().getBasicType()) { case EbtFloat: constVar->c = new ConstFloat(constunion->getUnionArrayPointer()->getFConst()); break; default: error("Unknown type", constunion->getLine().first_line); } value.v = constVar; return value; } else if (aggregate != nullptr) { switch (aggregate->getOp()) { case EOpConstructVec4: { auto vector = new PVector; for (size_t i = 0; i < aggregate->getSequence().size(); ++i) { vector->el.push_back(parseValue(aggregate->getSequence()[i]->getAsTyped())); } ParsedValue value; value.v = vector; value.p = aggregate->getLine().first_line; return value; } default: error("Unknown aggregate", constunion->getLine().first_line); } } error("Unsupported value expression", e->getLine().first_line); ParsedValue value; value.v = nullptr; value.p = e->getLine().first_line; return value; /*switch (e.expr) { case EField(ef, s): return { v : PField(parseValue(ef),s), p : e.pos }; case EConst(c): switch( c ) { case CIdent(i) #if !haxe3 , CType(i) #end: switch( i ) { case "null": return { v : PConst(CNull), p : e.pos }; case "true": return { v : PConst(CBool(true)), p : e.pos }; case "false": return { v : PConst(CBool(false)), p : e.pos }; default: return { v : PVar(i), p : e.pos }; } case CInt(v): return { v : PConst(CInt(Std.parseInt(v))), p : e.pos }; case CFloat(f): return { v : PConst(CFloat(Std.parseFloat(f))), p : e.pos }; default: } case EUnop(OpNeg, _, { expr : EConst(CInt(v)) } ): return { v : PConst(CInt(-Std.parseInt(v))), p : e.pos }; case EUnop(op, _, e1): var op = switch( op ) { case OpNeg: CNeg; case OpNot: CNot; default: error("Unsupported operation", e.pos); } return { v : PUnop(op,parseValue(e1)), p : e.pos }; case ECall(c, params): switch( c.expr ) { case EField(v, f): return makeCall(f, [v].concat(params), e.pos); case EConst(c): switch( c ) { case CIdent(i) #if !haxe3 , CType(i) #end: return makeCall(i, params, e.pos); default: } default: } case EArrayDecl(values): var vl = []; for( v in values ) vl.push(parseValue(v)); return { v : PVector(vl), p : e.pos }; case EParenthesis(k): var v = parseValue(k); v.p = e.pos; return v; case EIf(ec, eif, eelse), ETernary(ec,eif,eelse): var vcond = parseValue(ec); var vif = parseValue(eif); if( eelse == null ) error("'if' needs an 'else'", e.pos); var velse = parseValue(eelse); return { v : PCond(vcond, vif, velse), p : e.pos }; case EArray(e1, e2): var e1 = parseValue(e1); var e2 = parseValue(e2); return { v : PRow(e1, e2), p : e.pos }; default: } */ }