// // 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()) { std::stringstream extraInfoStream; extraInfoStream << "matrix field selection out of range '" << index << "'"; std::string extraInfo = extraInfoStream.str(); error(line, "", "[", extraInfo.c_str()); 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; }
// // This function returns the value of a particular field inside a constant structure from the symbol table. // If there is an embedded/nested struct, it appropriately calls addConstStructNested or addConstStructFromAggr // function and returns the parse-tree with the values of the embedded/nested struct. // TIntermTyped* TParseContext::addConstStruct(TString& identifier, TIntermTyped* node, TSourceLoc line) { const TTypeList* fields = node->getType().getStruct(); TIntermTyped *typedNode; int instanceSize = 0; unsigned int index = 0; TIntermConstantUnion *tempConstantNode = node->getAsConstantUnion(); for ( index = 0; index < fields->size(); ++index) { if ((*fields)[index].type->getFieldName() == identifier) { break; } else { instanceSize += (*fields)[index].type->getObjectSize(); } } if (tempConstantNode) { ConstantUnion* constArray = tempConstantNode->getUnionArrayPointer(); typedNode = intermediate.addConstantUnion(constArray+instanceSize, tempConstantNode->getType(), line); // type will be changed in the calling function } else { error(line, "Cannot offset into the structure", "Error", ""); recover(); return 0; } return typedNode; }
// // This function returns an element of an array accessed from a constant array. The values are retrieved from // the symbol table and parse-tree is built for the type of the element. The input // to the function could either be a symbol node (a[0] where a is a constant array)that represents a // constant array or it could be the tree representation of the constant array (s.a1[0] where s is a constant structure) // TIntermTyped* TParseContext::addConstArrayNode(int index, TIntermTyped* node, TSourceLoc line) { TIntermTyped* typedNode; TIntermConstantUnion* tempConstantNode = node->getAsConstantUnion(); TType arrayElementType = node->getType(); arrayElementType.clearArrayness(); if (index >= node->getType().getArraySize()) { error(line, "", "[", "array field selection out of range '%d'", index); recover(); index = 0; } int arrayElementSize = arrayElementType.getObjectSize(); if (tempConstantNode) { constUnion* unionArray = tempConstantNode->getUnionArrayPointer(); typedNode = intermediate.addConstantUnion(&unionArray[arrayElementSize * index], tempConstantNode->getType(), line); } else { error(line, "Cannot offset into the array", "Error", ""); recover(); return 0; } 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; }
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; } }
// // This function returns an element of an array accessed from a constant array. The values are retrieved from // the symbol table and parse-tree is built for the type of the element. The input // to the function could either be a symbol node (a[0] where a is a constant array)that represents a // constant array or it could be the tree representation of the constant array (s.a1[0] where s is a constant structure) // TIntermTyped* TParseContext::addConstArrayNode(int index, TIntermTyped* node, TSourceLoc line) { TIntermTyped* typedNode; TIntermConstantUnion* tempConstantNode = node->getAsConstantUnion(); TType arrayElementType = node->getType(); arrayElementType.clearArrayness(); if (index >= node->getType().getArraySize()) { std::stringstream extraInfoStream; extraInfoStream << "array field selection out of range '" << index << "'"; std::string extraInfo = extraInfoStream.str(); error(line, "", "[", extraInfo.c_str()); recover(); index = 0; } int arrayElementSize = arrayElementType.getObjectSize(); if (tempConstantNode) { ConstantUnion* unionArray = tempConstantNode->getUnionArrayPointer(); typedNode = intermediate.addConstantUnion(&unionArray[arrayElementSize * index], tempConstantNode->getType(), line); } else { error(line, "Cannot offset into the array", "Error"); recover(); return 0; } return typedNode; }
// // 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 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; }
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: } */ }