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