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