1 // Copyright 2016 The SwiftShader Authors. All Rights Reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #include "ParseHelper.h" 16 17 // 18 // Use this class to carry along data from node to node in 19 // the traversal 20 // 21 class TConstTraverser : public TIntermTraverser { 22 public: 23 TConstTraverser(ConstantUnion* cUnion, bool singleConstParam, TOperator constructType, TInfoSink& sink, TType& t) 24 : error(false), 25 index(0), 26 unionArray(cUnion), 27 type(t), 28 constructorType(constructType), 29 singleConstantParam(singleConstParam), 30 infoSink(sink), 31 size(0), 32 isMatrix(false), 33 matrixSize(0) { 34 } 35 36 bool error; 37 38 protected: 39 void visitSymbol(TIntermSymbol*); 40 void visitConstantUnion(TIntermConstantUnion*); 41 bool visitBinary(Visit visit, TIntermBinary*); 42 bool visitUnary(Visit visit, TIntermUnary*); 43 bool visitSelection(Visit visit, TIntermSelection*); 44 bool visitAggregate(Visit visit, TIntermAggregate*); 45 bool visitLoop(Visit visit, TIntermLoop*); 46 bool visitBranch(Visit visit, TIntermBranch*); 47 48 size_t index; 49 ConstantUnion *unionArray; 50 TType type; 51 TOperator constructorType; 52 bool singleConstantParam; 53 TInfoSink& infoSink; 54 size_t size; // size of the constructor ( 4 for vec4) 55 bool isMatrix; 56 int matrixSize; // dimension of the matrix (nominal size and not the instance size) 57 }; 58 59 // 60 // The rest of the file are the traversal functions. The last one 61 // is the one that starts the traversal. 62 // 63 // Return true from interior nodes to have the external traversal 64 // continue on to children. If you process children yourself, 65 // return false. 66 // 67 68 void TConstTraverser::visitSymbol(TIntermSymbol* node) 69 { 70 infoSink.info.message(EPrefixInternalError, "Symbol Node found in constant constructor", node->getLine()); 71 return; 72 } 73 74 bool TConstTraverser::visitBinary(Visit visit, TIntermBinary* node) 75 { 76 TQualifier qualifier = node->getType().getQualifier(); 77 78 if (qualifier != EvqConstExpr) { 79 TString buf; 80 buf.append("'constructor' : assigning non-constant to "); 81 buf.append(type.getCompleteString()); 82 infoSink.info.message(EPrefixError, buf.c_str(), node->getLine()); 83 error = true; 84 return false; 85 } 86 87 infoSink.info.message(EPrefixInternalError, "Binary Node found in constant constructor", node->getLine()); 88 89 return false; 90 } 91 92 bool TConstTraverser::visitUnary(Visit visit, TIntermUnary* node) 93 { 94 TString buf; 95 buf.append("'constructor' : assigning non-constant to "); 96 buf.append(type.getCompleteString()); 97 infoSink.info.message(EPrefixError, buf.c_str(), node->getLine()); 98 error = true; 99 return false; 100 } 101 102 bool TConstTraverser::visitAggregate(Visit visit, TIntermAggregate* node) 103 { 104 if (!node->isConstructor() && node->getOp() != EOpComma) { 105 TString buf; 106 buf.append("'constructor' : assigning non-constant to "); 107 buf.append(type.getCompleteString()); 108 infoSink.info.message(EPrefixError, buf.c_str(), node->getLine()); 109 error = true; 110 return false; 111 } 112 113 if (node->getSequence().size() == 0) { 114 error = true; 115 return false; 116 } 117 118 bool flag = node->getSequence().size() == 1 && node->getSequence()[0]->getAsTyped()->getAsConstantUnion(); 119 if (flag) 120 { 121 singleConstantParam = true; 122 constructorType = node->getOp(); 123 size = node->getType().getObjectSize(); 124 125 if (node->getType().isMatrix()) { 126 isMatrix = true; 127 matrixSize = node->getType().getNominalSize(); 128 } 129 } 130 131 for (TIntermSequence::iterator p = node->getSequence().begin(); 132 p != node->getSequence().end(); p++) { 133 134 if (node->getOp() == EOpComma) 135 index = 0; 136 137 (*p)->traverse(this); 138 } 139 if (flag) 140 { 141 singleConstantParam = false; 142 constructorType = EOpNull; 143 size = 0; 144 isMatrix = false; 145 matrixSize = 0; 146 } 147 return false; 148 } 149 150 bool TConstTraverser::visitSelection(Visit visit, TIntermSelection* node) 151 { 152 infoSink.info.message(EPrefixInternalError, "Selection Node found in constant constructor", node->getLine()); 153 error = true; 154 return false; 155 } 156 157 void TConstTraverser::visitConstantUnion(TIntermConstantUnion* node) 158 { 159 if (!node->getUnionArrayPointer()) 160 { 161 // The constant was not initialized, this should already have been logged 162 assert(infoSink.info.size() != 0); 163 return; 164 } 165 166 ConstantUnion* leftUnionArray = unionArray; 167 size_t instanceSize = type.getObjectSize(); 168 TBasicType basicType = type.getBasicType(); 169 170 if (index >= instanceSize) 171 return; 172 173 if (!singleConstantParam) { 174 size_t size = node->getType().getObjectSize(); 175 176 ConstantUnion *rightUnionArray = node->getUnionArrayPointer(); 177 for(size_t i = 0; i < size; i++) { 178 if (index >= instanceSize) 179 return; 180 leftUnionArray[index].cast(basicType, rightUnionArray[i]); 181 182 (index)++; 183 } 184 } else { 185 size_t totalSize = index + size; 186 ConstantUnion *rightUnionArray = node->getUnionArrayPointer(); 187 if (!isMatrix) { 188 int count = 0; 189 for(size_t i = index; i < totalSize; i++) { 190 if (i >= instanceSize) 191 return; 192 193 leftUnionArray[i].cast(basicType, rightUnionArray[count]); 194 195 (index)++; 196 197 if (node->getType().getObjectSize() > 1) 198 count++; 199 } 200 } else { // for matrix constructors 201 int count = 0; 202 int element = index; 203 for(size_t i = index; i < totalSize; i++) { 204 if (i >= instanceSize) 205 return; 206 if (element - i == 0 || (i - element) % (matrixSize + 1) == 0 ) 207 leftUnionArray[i].cast(basicType, rightUnionArray[0]); 208 else 209 leftUnionArray[i].setFConst(0.0f); 210 211 (index)++; 212 213 if (node->getType().getObjectSize() > 1) 214 count++; 215 } 216 } 217 } 218 } 219 220 bool TConstTraverser::visitLoop(Visit visit, TIntermLoop* node) 221 { 222 infoSink.info.message(EPrefixInternalError, "Loop Node found in constant constructor", node->getLine()); 223 error = true; 224 return false; 225 } 226 227 bool TConstTraverser::visitBranch(Visit visit, TIntermBranch* node) 228 { 229 infoSink.info.message(EPrefixInternalError, "Branch Node found in constant constructor", node->getLine()); 230 error = true; 231 return false; 232 } 233 234 // 235 // This function is the one to call externally to start the traversal. 236 // Individual functions can be initialized to 0 to skip processing of that 237 // type of node. It's children will still be processed. 238 // 239 bool TIntermediate::parseConstTree(const TSourceLoc& line, TIntermNode* root, ConstantUnion* unionArray, TOperator constructorType, TType t, bool singleConstantParam) 240 { 241 if (root == 0) 242 return false; 243 244 TConstTraverser it(unionArray, singleConstantParam, constructorType, infoSink, t); 245 246 root->traverse(&it); 247 if (it.error) 248 return true; 249 else 250 return false; 251 } 252