| // Copyright 2016 The SwiftShader Authors. All Rights Reserved. | |
| // | |
| // Licensed under the Apache License, Version 2.0 (the "License"); | |
| // you may not use this file except in compliance with the License. | |
| // You may obtain a copy of the License at | |
| // | |
| // http://www.apache.org/licenses/LICENSE-2.0 | |
| // | |
| // Unless required by applicable law or agreed to in writing, software | |
| // distributed under the License is distributed on an "AS IS" BASIS, | |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| // See the License for the specific language governing permissions and | |
| // limitations under the License. | |
| #include "ParseHelper.h" | |
| // | |
| // Use this class to carry along data from node to node in | |
| // the traversal | |
| // | |
| class TConstTraverser : public TIntermTraverser { | |
| public: | |
| TConstTraverser(ConstantUnion* cUnion, bool singleConstParam, TOperator constructType, TInfoSink& sink, TType& t) | |
| : error(false), | |
| index(0), | |
| unionArray(cUnion), | |
| type(t), | |
| constructorType(constructType), | |
| singleConstantParam(singleConstParam), | |
| infoSink(sink), | |
| size(0), | |
| isMatrix(false), | |
| matrixRows(0) { | |
| } | |
| bool error; | |
| protected: | |
| void visitSymbol(TIntermSymbol*); | |
| void visitConstantUnion(TIntermConstantUnion*); | |
| bool visitBinary(Visit visit, TIntermBinary*); | |
| bool visitUnary(Visit visit, TIntermUnary*); | |
| bool visitSelection(Visit visit, TIntermSelection*); | |
| bool visitAggregate(Visit visit, TIntermAggregate*); | |
| bool visitLoop(Visit visit, TIntermLoop*); | |
| bool visitBranch(Visit visit, TIntermBranch*); | |
| size_t index; | |
| ConstantUnion *unionArray; | |
| TType type; | |
| TOperator constructorType; | |
| bool singleConstantParam; | |
| TInfoSink& infoSink; | |
| size_t size; // size of the constructor ( 4 for vec4) | |
| bool isMatrix; | |
| int matrixRows; // number of rows in the matrix (nominal size and not the instance size) | |
| }; | |
| // | |
| // The rest of the file are the traversal functions. The last one | |
| // is the one that starts the traversal. | |
| // | |
| // Return true from interior nodes to have the external traversal | |
| // continue on to children. If you process children yourself, | |
| // return false. | |
| // | |
| void TConstTraverser::visitSymbol(TIntermSymbol* node) | |
| { | |
| infoSink.info.message(EPrefixInternalError, "Symbol Node found in constant constructor", node->getLine()); | |
| return; | |
| } | |
| bool TConstTraverser::visitBinary(Visit visit, TIntermBinary* node) | |
| { | |
| TQualifier qualifier = node->getType().getQualifier(); | |
| if (qualifier != EvqConstExpr) { | |
| TString buf; | |
| buf.append("'constructor' : assigning non-constant to "); | |
| buf.append(type.getCompleteString()); | |
| infoSink.info.message(EPrefixError, buf.c_str(), node->getLine()); | |
| error = true; | |
| return false; | |
| } | |
| infoSink.info.message(EPrefixInternalError, "Binary Node found in constant constructor", node->getLine()); | |
| return false; | |
| } | |
| bool TConstTraverser::visitUnary(Visit visit, TIntermUnary* node) | |
| { | |
| TString buf; | |
| buf.append("'constructor' : assigning non-constant to "); | |
| buf.append(type.getCompleteString()); | |
| infoSink.info.message(EPrefixError, buf.c_str(), node->getLine()); | |
| error = true; | |
| return false; | |
| } | |
| bool TConstTraverser::visitAggregate(Visit visit, TIntermAggregate* node) | |
| { | |
| if (!node->isConstructor() && node->getOp() != EOpComma) { | |
| TString buf; | |
| buf.append("'constructor' : assigning non-constant to "); | |
| buf.append(type.getCompleteString()); | |
| infoSink.info.message(EPrefixError, buf.c_str(), node->getLine()); | |
| error = true; | |
| return false; | |
| } | |
| if (node->getSequence().size() == 0) { | |
| error = true; | |
| return false; | |
| } | |
| bool flag = node->getSequence().size() == 1 && node->getSequence()[0]->getAsTyped()->getAsConstantUnion(); | |
| if (flag) | |
| { | |
| singleConstantParam = true; | |
| constructorType = node->getOp(); | |
| size = node->getType().getObjectSize(); | |
| if (node->getType().isMatrix()) { | |
| isMatrix = true; | |
| matrixRows = node->getType().getSecondarySize(); | |
| } | |
| } | |
| for (TIntermSequence::iterator p = node->getSequence().begin(); | |
| p != node->getSequence().end(); p++) { | |
| if (node->getOp() == EOpComma) | |
| index = 0; | |
| (*p)->traverse(this); | |
| } | |
| if (flag) | |
| { | |
| singleConstantParam = false; | |
| constructorType = EOpNull; | |
| size = 0; | |
| isMatrix = false; | |
| matrixRows = 0; | |
| } | |
| return false; | |
| } | |
| bool TConstTraverser::visitSelection(Visit visit, TIntermSelection* node) | |
| { | |
| infoSink.info.message(EPrefixInternalError, "Selection Node found in constant constructor", node->getLine()); | |
| error = true; | |
| return false; | |
| } | |
| void TConstTraverser::visitConstantUnion(TIntermConstantUnion* node) | |
| { | |
| if (!node->getUnionArrayPointer()) | |
| { | |
| // The constant was not initialized, this should already have been logged | |
| assert(infoSink.info.size() != 0); | |
| return; | |
| } | |
| ConstantUnion* leftUnionArray = unionArray; | |
| size_t instanceSize = type.getObjectSize(); | |
| TBasicType basicType = type.getBasicType(); | |
| if (index >= instanceSize) | |
| return; | |
| if (!singleConstantParam) { | |
| size_t size = node->getType().getObjectSize(); | |
| ConstantUnion *rightUnionArray = node->getUnionArrayPointer(); | |
| for(size_t i = 0; i < size; i++) { | |
| if (index >= instanceSize) | |
| return; | |
| leftUnionArray[index].cast(basicType, rightUnionArray[i]); | |
| (index)++; | |
| } | |
| } else { | |
| size_t totalSize = index + size; | |
| ConstantUnion *rightUnionArray = node->getUnionArrayPointer(); | |
| if (!isMatrix) { | |
| int count = 0; | |
| for(size_t i = index; i < totalSize; i++) { | |
| if (i >= instanceSize) | |
| return; | |
| leftUnionArray[i].cast(basicType, rightUnionArray[count]); | |
| (index)++; | |
| if (node->getType().getObjectSize() > 1) | |
| count++; | |
| } | |
| } else { // for matrix constructors | |
| int count = 0; | |
| int element = index; | |
| for(size_t i = index; i < totalSize; i++) { | |
| if (i >= instanceSize) | |
| return; | |
| if (element - i == 0 || (i - element) % (matrixRows + 1) == 0 ) | |
| leftUnionArray[i].cast(basicType, rightUnionArray[0]); | |
| else | |
| leftUnionArray[i].setFConst(0.0f); | |
| (index)++; | |
| if (node->getType().getObjectSize() > 1) | |
| count++; | |
| } | |
| } | |
| } | |
| } | |
| bool TConstTraverser::visitLoop(Visit visit, TIntermLoop* node) | |
| { | |
| infoSink.info.message(EPrefixInternalError, "Loop Node found in constant constructor", node->getLine()); | |
| error = true; | |
| return false; | |
| } | |
| bool TConstTraverser::visitBranch(Visit visit, TIntermBranch* node) | |
| { | |
| infoSink.info.message(EPrefixInternalError, "Branch Node found in constant constructor", node->getLine()); | |
| error = true; | |
| return false; | |
| } | |
| // | |
| // This function is the one to call externally to start the traversal. | |
| // Individual functions can be initialized to 0 to skip processing of that | |
| // type of node. It's children will still be processed. | |
| // | |
| bool TIntermediate::parseConstTree(const TSourceLoc& line, TIntermNode* root, ConstantUnion* unionArray, TOperator constructorType, TType t, bool singleConstantParam) | |
| { | |
| if (root == 0) | |
| return false; | |
| TConstTraverser it(unionArray, singleConstantParam, constructorType, infoSink, t); | |
| root->traverse(&it); | |
| if (it.error) | |
| return true; | |
| else | |
| return false; | |
| } |