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 "localintermediate.h" 16 #include "SymbolTable.h" 17 18 // 19 // Two purposes: 20 // 1. Show an example of how to iterate tree. Functions can 21 // also directly call Traverse() on children themselves to 22 // have finer grained control over the process than shown here. 23 // See the last function for how to get started. 24 // 2. Print out a text based description of the tree. 25 // 26 27 // 28 // Use this class to carry along data from node to node in 29 // the traversal 30 // 31 class TOutputTraverser : public TIntermTraverser { 32 public: 33 TOutputTraverser(TInfoSinkBase& i) : sink(i) { } 34 TInfoSinkBase& sink; 35 36 protected: 37 void visitSymbol(TIntermSymbol*); 38 void visitConstantUnion(TIntermConstantUnion*); 39 bool visitBinary(Visit visit, TIntermBinary*); 40 bool visitUnary(Visit visit, TIntermUnary*); 41 bool visitSelection(Visit visit, TIntermSelection*); 42 bool visitAggregate(Visit visit, TIntermAggregate*); 43 bool visitLoop(Visit visit, TIntermLoop*); 44 bool visitBranch(Visit visit, TIntermBranch*); 45 }; 46 47 TString TType::getCompleteString() const 48 { 49 TStringStream stream; 50 51 if (qualifier != EvqTemporary && qualifier != EvqGlobal) 52 stream << getQualifierString() << " " << getPrecisionString() << " "; 53 if (array) 54 stream << "array of "; 55 if (isMatrix()) 56 stream << static_cast<int>(primarySize) << "X" << static_cast<int>(secondarySize) << " matrix of "; 57 else if(primarySize > 1) 58 stream << static_cast<int>(primarySize) << "-component vector of "; 59 60 stream << getBasicString(); 61 return stream.str(); 62 } 63 64 // 65 // Helper functions for printing, not part of traversing. 66 // 67 68 void OutputTreeText(TInfoSinkBase& sink, TIntermNode* node, const int depth) 69 { 70 int i; 71 72 sink.location(node->getLine()); 73 74 for (i = 0; i < depth; ++i) 75 sink << " "; 76 } 77 78 // 79 // The rest of the file are the traversal functions. The last one 80 // is the one that starts the traversal. 81 // 82 // Return true from interior nodes to have the external traversal 83 // continue on to children. If you process children yourself, 84 // return false. 85 // 86 87 void TOutputTraverser::visitSymbol(TIntermSymbol* node) 88 { 89 OutputTreeText(sink, node, mDepth); 90 91 sink << "'" << node->getSymbol() << "' "; 92 sink << "(" << node->getCompleteString() << ")\n"; 93 } 94 95 bool TOutputTraverser::visitBinary(Visit visit, TIntermBinary* node) 96 { 97 TInfoSinkBase& out = sink; 98 99 OutputTreeText(out, node, mDepth); 100 101 switch (node->getOp()) { 102 case EOpAssign: out << "move second child to first child"; break; 103 case EOpInitialize: out << "initialize first child with second child"; break; 104 case EOpAddAssign: out << "add second child into first child"; break; 105 case EOpSubAssign: out << "subtract second child into first child"; break; 106 case EOpMulAssign: out << "multiply second child into first child"; break; 107 case EOpVectorTimesMatrixAssign: out << "matrix mult second child into first child"; break; 108 case EOpVectorTimesScalarAssign: out << "vector scale second child into first child"; break; 109 case EOpMatrixTimesScalarAssign: out << "matrix scale second child into first child"; break; 110 case EOpMatrixTimesMatrixAssign: out << "matrix mult second child into first child"; break; 111 case EOpDivAssign: out << "divide second child into first child"; break; 112 case EOpIModAssign: out << "modulo second child into first child"; break; 113 case EOpBitShiftLeftAssign: out << "bit-wise shift first child left by second child"; break; 114 case EOpBitShiftRightAssign: out << "bit-wise shift first child right by second child"; break; 115 case EOpBitwiseAndAssign: out << "bit-wise and second child into first child"; break; 116 case EOpBitwiseXorAssign: out << "bit-wise xor second child into first child"; break; 117 case EOpBitwiseOrAssign: out << "bit-wise or second child into first child"; break; 118 case EOpIndexDirect: out << "direct index"; break; 119 case EOpIndexIndirect: out << "indirect index"; break; 120 case EOpIndexDirectStruct: out << "direct index for structure"; break; 121 case EOpVectorSwizzle: out << "vector swizzle"; break; 122 123 case EOpAdd: out << "add"; break; 124 case EOpSub: out << "subtract"; break; 125 case EOpMul: out << "component-wise multiply"; break; 126 case EOpDiv: out << "divide"; break; 127 case EOpIMod: out << "modulo"; break; 128 case EOpBitShiftLeft: out << "bit-wise shift left"; break; 129 case EOpBitShiftRight: out << "bit-wise shift right"; break; 130 case EOpBitwiseAnd: out << "bit-wise and"; break; 131 case EOpBitwiseXor: out << "bit-wise xor"; break; 132 case EOpBitwiseOr: out << "bit-wise or"; break; 133 case EOpEqual: out << "Compare Equal"; break; 134 case EOpNotEqual: out << "Compare Not Equal"; break; 135 case EOpLessThan: out << "Compare Less Than"; break; 136 case EOpGreaterThan: out << "Compare Greater Than"; break; 137 case EOpLessThanEqual: out << "Compare Less Than or Equal"; break; 138 case EOpGreaterThanEqual: out << "Compare Greater Than or Equal"; break; 139 140 case EOpVectorTimesScalar: out << "vector-scale"; break; 141 case EOpVectorTimesMatrix: out << "vector-times-matrix"; break; 142 case EOpMatrixTimesVector: out << "matrix-times-vector"; break; 143 case EOpMatrixTimesScalar: out << "matrix-scale"; break; 144 case EOpMatrixTimesMatrix: out << "matrix-multiply"; break; 145 146 case EOpLogicalOr: out << "logical-or"; break; 147 case EOpLogicalXor: out << "logical-xor"; break; 148 case EOpLogicalAnd: out << "logical-and"; break; 149 default: out << "<unknown op>"; 150 } 151 152 out << " (" << node->getCompleteString() << ")"; 153 154 out << "\n"; 155 156 return true; 157 } 158 159 bool TOutputTraverser::visitUnary(Visit visit, TIntermUnary* node) 160 { 161 TInfoSinkBase& out = sink; 162 163 OutputTreeText(out, node, mDepth); 164 165 switch (node->getOp()) { 166 case EOpNegative: out << "Negate value"; break; 167 case EOpVectorLogicalNot: 168 case EOpLogicalNot: out << "Negate conditional"; break; 169 case EOpBitwiseNot: out << "bit-wise not"; break; 170 171 case EOpPostIncrement: out << "Post-Increment"; break; 172 case EOpPostDecrement: out << "Post-Decrement"; break; 173 case EOpPreIncrement: out << "Pre-Increment"; break; 174 case EOpPreDecrement: out << "Pre-Decrement"; break; 175 176 case EOpRadians: out << "radians"; break; 177 case EOpDegrees: out << "degrees"; break; 178 case EOpSin: out << "sine"; break; 179 case EOpCos: out << "cosine"; break; 180 case EOpTan: out << "tangent"; break; 181 case EOpAsin: out << "arc sine"; break; 182 case EOpAcos: out << "arc cosine"; break; 183 case EOpAtan: out << "arc tangent"; break; 184 case EOpSinh: out << "hyperbolic sine"; break; 185 case EOpCosh: out << "hyperbolic cosine"; break; 186 case EOpTanh: out << "hyperbolic tangent"; break; 187 case EOpAsinh: out << "arc hyperbolic sine"; break; 188 case EOpAcosh: out << "arc hyperbolic cosine"; break; 189 case EOpAtanh: out << "arc hyperbolic tangent"; break; 190 191 case EOpExp: out << "exp"; break; 192 case EOpLog: out << "log"; break; 193 case EOpExp2: out << "exp2"; break; 194 case EOpLog2: out << "log2"; break; 195 case EOpSqrt: out << "sqrt"; break; 196 case EOpInverseSqrt: out << "inverse sqrt"; break; 197 198 case EOpAbs: out << "Absolute value"; break; 199 case EOpSign: out << "Sign"; break; 200 case EOpFloor: out << "Floor"; break; 201 case EOpTrunc: out << "Trunc"; break; 202 case EOpRound: out << "Round"; break; 203 case EOpRoundEven: out << "RoundEven"; break; 204 case EOpCeil: out << "Ceiling"; break; 205 case EOpFract: out << "Fraction"; break; 206 case EOpIsNan: out << "Is not a number"; break; 207 case EOpIsInf: out << "Is infinity"; break; 208 209 case EOpFloatBitsToInt: out << "float bits to int"; break; 210 case EOpFloatBitsToUint: out << "float bits to uint"; break; 211 case EOpIntBitsToFloat: out << "int bits to float"; break; 212 case EOpUintBitsToFloat: out << "uint bits to float"; break; 213 214 case EOpPackSnorm2x16: out << "pack Snorm 2x16"; break; 215 case EOpPackUnorm2x16: out << "pack Unorm 2x16"; break; 216 case EOpPackHalf2x16: out << "pack half 2x16"; break; 217 218 case EOpUnpackSnorm2x16: out << "unpack Snorm 2x16"; break; 219 case EOpUnpackUnorm2x16: out << "unpack Unorm 2x16"; break; 220 case EOpUnpackHalf2x16: out << "unpack half 2x16"; break; 221 222 case EOpLength: out << "length"; break; 223 case EOpNormalize: out << "normalize"; break; 224 // case EOpDPdx: out << "dPdx"; break; 225 // case EOpDPdy: out << "dPdy"; break; 226 // case EOpFwidth: out << "fwidth"; break; 227 228 case EOpDeterminant: out << "determinant"; break; 229 case EOpTranspose: out << "transpose"; break; 230 case EOpInverse: out << "inverse"; break; 231 232 case EOpAny: out << "any"; break; 233 case EOpAll: out << "all"; break; 234 235 default: out.message(EPrefixError, "Bad unary op"); 236 } 237 238 out << " (" << node->getCompleteString() << ")"; 239 240 out << "\n"; 241 242 return true; 243 } 244 245 bool TOutputTraverser::visitAggregate(Visit visit, TIntermAggregate* node) 246 { 247 TInfoSinkBase& out = sink; 248 249 if (node->getOp() == EOpNull) { 250 out.message(EPrefixError, "node is still EOpNull!"); 251 return true; 252 } 253 254 OutputTreeText(out, node, mDepth); 255 256 switch (node->getOp()) { 257 case EOpSequence: out << "Sequence\n"; return true; 258 case EOpComma: out << "Comma\n"; return true; 259 case EOpFunction: out << "Function Definition: " << node->getName(); break; 260 case EOpFunctionCall: out << "Function Call: " << node->getName(); break; 261 case EOpParameters: out << "Function Parameters: "; break; 262 263 case EOpConstructFloat: out << "Construct float"; break; 264 case EOpConstructVec2: out << "Construct vec2"; break; 265 case EOpConstructVec3: out << "Construct vec3"; break; 266 case EOpConstructVec4: out << "Construct vec4"; break; 267 case EOpConstructBool: out << "Construct bool"; break; 268 case EOpConstructBVec2: out << "Construct bvec2"; break; 269 case EOpConstructBVec3: out << "Construct bvec3"; break; 270 case EOpConstructBVec4: out << "Construct bvec4"; break; 271 case EOpConstructInt: out << "Construct int"; break; 272 case EOpConstructIVec2: out << "Construct ivec2"; break; 273 case EOpConstructIVec3: out << "Construct ivec3"; break; 274 case EOpConstructIVec4: out << "Construct ivec4"; break; 275 case EOpConstructUInt: out << "Construct uint"; break; 276 case EOpConstructUVec2: out << "Construct uvec2"; break; 277 case EOpConstructUVec3: out << "Construct uvec3"; break; 278 case EOpConstructUVec4: out << "Construct uvec4"; break; 279 case EOpConstructMat2: out << "Construct mat2"; break; 280 case EOpConstructMat2x3: out << "Construct mat2x3"; break; 281 case EOpConstructMat2x4: out << "Construct mat2x4"; break; 282 case EOpConstructMat3x2: out << "Construct mat3x2"; break; 283 case EOpConstructMat3: out << "Construct mat3"; break; 284 case EOpConstructMat3x4: out << "Construct mat3x4"; break; 285 case EOpConstructMat4x2: out << "Construct mat4x2"; break; 286 case EOpConstructMat4x3: out << "Construct mat4x3"; break; 287 case EOpConstructMat4: out << "Construct mat4"; break; 288 case EOpConstructStruct: out << "Construct structure"; break; 289 290 case EOpLessThan: out << "Compare Less Than"; break; 291 case EOpGreaterThan: out << "Compare Greater Than"; break; 292 case EOpLessThanEqual: out << "Compare Less Than or Equal"; break; 293 case EOpGreaterThanEqual: out << "Compare Greater Than or Equal"; break; 294 case EOpVectorEqual: out << "Equal"; break; 295 case EOpVectorNotEqual: out << "NotEqual"; break; 296 297 case EOpMod: out << "mod"; break; 298 case EOpModf: out << "modf"; break; 299 case EOpPow: out << "pow"; break; 300 301 case EOpAtan: out << "arc tangent"; break; 302 303 case EOpMin: out << "min"; break; 304 case EOpMax: out << "max"; break; 305 case EOpClamp: out << "clamp"; break; 306 case EOpMix: out << "mix"; break; 307 case EOpStep: out << "step"; break; 308 case EOpSmoothStep: out << "smoothstep"; break; 309 310 case EOpFloatBitsToInt: out << "floatBitsToInt"; break; 311 case EOpFloatBitsToUint: out << "floatBitsToUint"; break; 312 case EOpIntBitsToFloat: out << "intBitsToFloat"; break; 313 case EOpUintBitsToFloat: out << "uintBitsToFloat"; break; 314 315 case EOpDistance: out << "distance"; break; 316 case EOpDot: out << "dot-product"; break; 317 case EOpCross: out << "cross-product"; break; 318 case EOpFaceForward: out << "face-forward"; break; 319 case EOpReflect: out << "reflect"; break; 320 case EOpRefract: out << "refract"; break; 321 case EOpMul: out << "component-wise multiply"; break; 322 case EOpOuterProduct: out << "outer product"; break; 323 324 default: out.message(EPrefixError, "Bad aggregation op"); 325 } 326 327 if (node->getOp() != EOpSequence && node->getOp() != EOpParameters) 328 out << " (" << node->getCompleteString() << ")"; 329 330 out << "\n"; 331 332 return true; 333 } 334 335 bool TOutputTraverser::visitSelection(Visit visit, TIntermSelection* node) 336 { 337 TInfoSinkBase& out = sink; 338 339 OutputTreeText(out, node, mDepth); 340 341 out << "Test condition and select"; 342 out << " (" << node->getCompleteString() << ")\n"; 343 344 ++mDepth; 345 346 OutputTreeText(sink, node, mDepth); 347 out << "Condition\n"; 348 node->getCondition()->traverse(this); 349 350 OutputTreeText(sink, node, mDepth); 351 if (node->getTrueBlock()) { 352 out << "true case\n"; 353 node->getTrueBlock()->traverse(this); 354 } else 355 out << "true case is null\n"; 356 357 if (node->getFalseBlock()) { 358 OutputTreeText(sink, node, mDepth); 359 out << "false case\n"; 360 node->getFalseBlock()->traverse(this); 361 } 362 363 --mDepth; 364 365 return false; 366 } 367 368 void TOutputTraverser::visitConstantUnion(TIntermConstantUnion* node) 369 { 370 TInfoSinkBase& out = sink; 371 372 size_t size = node->getType().getObjectSize(); 373 374 for(size_t i = 0; i < size; i++) { 375 OutputTreeText(out, node, mDepth); 376 switch (node->getUnionArrayPointer()[i].getType()) { 377 case EbtBool: 378 if (node->getUnionArrayPointer()[i].getBConst()) 379 out << "true"; 380 else 381 out << "false"; 382 383 out << " (" << "const bool" << ")"; 384 out << "\n"; 385 break; 386 case EbtFloat: 387 out << node->getUnionArrayPointer()[i].getFConst(); 388 out << " (const float)\n"; 389 break; 390 case EbtInt: 391 out << node->getUnionArrayPointer()[i].getIConst(); 392 out << " (const int)\n"; 393 break; 394 case EbtUInt: 395 out << node->getUnionArrayPointer()[i].getUConst(); 396 out << " (const uint)\n"; 397 break; 398 default: 399 out.message(EPrefixInternalError, "Unknown constant", node->getLine()); 400 break; 401 } 402 } 403 } 404 405 bool TOutputTraverser::visitLoop(Visit visit, TIntermLoop* node) 406 { 407 TInfoSinkBase& out = sink; 408 409 OutputTreeText(out, node, mDepth); 410 411 out << "Loop with condition "; 412 if (node->getType() == ELoopDoWhile) 413 out << "not "; 414 out << "tested first\n"; 415 416 ++mDepth; 417 418 OutputTreeText(sink, node, mDepth); 419 if (node->getCondition()) { 420 out << "Loop Condition\n"; 421 node->getCondition()->traverse(this); 422 } else 423 out << "No loop condition\n"; 424 425 OutputTreeText(sink, node, mDepth); 426 if (node->getBody()) { 427 out << "Loop Body\n"; 428 node->getBody()->traverse(this); 429 } else 430 out << "No loop body\n"; 431 432 if (node->getExpression()) { 433 OutputTreeText(sink, node, mDepth); 434 out << "Loop Terminal Expression\n"; 435 node->getExpression()->traverse(this); 436 } 437 438 --mDepth; 439 440 return false; 441 } 442 443 bool TOutputTraverser::visitBranch(Visit visit, TIntermBranch* node) 444 { 445 TInfoSinkBase& out = sink; 446 447 OutputTreeText(out, node, mDepth); 448 449 switch (node->getFlowOp()) { 450 case EOpKill: out << "Branch: Kill"; break; 451 case EOpBreak: out << "Branch: Break"; break; 452 case EOpContinue: out << "Branch: Continue"; break; 453 case EOpReturn: out << "Branch: Return"; break; 454 default: out << "Branch: Unknown Branch"; break; 455 } 456 457 if (node->getExpression()) { 458 out << " with expression\n"; 459 ++mDepth; 460 node->getExpression()->traverse(this); 461 --mDepth; 462 } else 463 out << "\n"; 464 465 return false; 466 } 467 468 // 469 // This function is the one to call externally to start the traversal. 470 // Individual functions can be initialized to 0 to skip processing of that 471 // type of node. It's children will still be processed. 472 // 473 void TIntermediate::outputTree(TIntermNode* root) 474 { 475 if (root == 0) 476 return; 477 478 TOutputTraverser it(infoSink.info); 479 480 root->traverse(&it); 481 } 482