1// 2//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. 3//Copyright (C) 2012-2016 LunarG, Inc. 4// 5//All rights reserved. 6// 7//Redistribution and use in source and binary forms, with or without 8//modification, are permitted provided that the following conditions 9//are met: 10// 11// Redistributions of source code must retain the above copyright 12// notice, this list of conditions and the following disclaimer. 13// 14// Redistributions in binary form must reproduce the above 15// copyright notice, this list of conditions and the following 16// disclaimer in the documentation and/or other materials provided 17// with the distribution. 18// 19// Neither the name of 3Dlabs Inc. Ltd. nor the names of its 20// contributors may be used to endorse or promote products derived 21// from this software without specific prior written permission. 22// 23//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 26//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 27//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 28//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 29//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 30//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 31//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 33//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 34//POSSIBILITY OF SUCH DAMAGE. 35// 36 37#include "localintermediate.h" 38#include "../Include/InfoSink.h" 39 40#ifdef _MSC_VER 41#include <float.h> 42#elif defined __ANDROID__ || defined __linux__ || __MINGW32__ || __MINGW64__ 43#include <cmath> 44#else 45#include <math.h> 46#endif 47 48namespace { 49 50bool is_positive_infinity(double x) { 51#ifdef _MSC_VER 52 return _fpclass(x) == _FPCLASS_PINF; 53#elif defined __ANDROID__ || defined __linux__ || __MINGW32__ || __MINGW64__ 54 return std::isinf(x) && (x >= 0); 55#else 56 return isinf(x) && (x >= 0); 57#endif 58} 59 60} 61 62namespace glslang { 63 64// 65// Two purposes: 66// 1. Show an example of how to iterate tree. Functions can 67// also directly call Traverse() on children themselves to 68// have finer grained control over the process than shown here. 69// See the last function for how to get started. 70// 2. Print out a text based description of the tree. 71// 72 73// 74// Use this class to carry along data from node to node in 75// the traversal 76// 77class TOutputTraverser : public TIntermTraverser { 78public: 79 TOutputTraverser(TInfoSink& i) : infoSink(i) { } 80 81 virtual bool visitBinary(TVisit, TIntermBinary* node); 82 virtual bool visitUnary(TVisit, TIntermUnary* node); 83 virtual bool visitAggregate(TVisit, TIntermAggregate* node); 84 virtual bool visitSelection(TVisit, TIntermSelection* node); 85 virtual void visitConstantUnion(TIntermConstantUnion* node); 86 virtual void visitSymbol(TIntermSymbol* node); 87 virtual bool visitLoop(TVisit, TIntermLoop* node); 88 virtual bool visitBranch(TVisit, TIntermBranch* node); 89 virtual bool visitSwitch(TVisit, TIntermSwitch* node); 90 91 TInfoSink& infoSink; 92protected: 93 TOutputTraverser(TOutputTraverser&); 94 TOutputTraverser& operator=(TOutputTraverser&); 95}; 96 97// 98// Helper functions for printing, not part of traversing. 99// 100 101static void OutputTreeText(TInfoSink& infoSink, const TIntermNode* node, const int depth) 102{ 103 int i; 104 105 infoSink.debug << node->getLoc().string << ":"; 106 if (node->getLoc().line) 107 infoSink.debug << node->getLoc().line; 108 else 109 infoSink.debug << "? "; 110 111 for (i = 0; i < depth; ++i) 112 infoSink.debug << " "; 113} 114 115// 116// The rest of the file are the traversal functions. The last one 117// is the one that starts the traversal. 118// 119// Return true from interior nodes to have the external traversal 120// continue on to children. If you process children yourself, 121// return false. 122// 123 124bool TOutputTraverser::visitBinary(TVisit /* visit */, TIntermBinary* node) 125{ 126 TInfoSink& out = infoSink; 127 128 OutputTreeText(out, node, depth); 129 130 switch (node->getOp()) { 131 case EOpAssign: out.debug << "move second child to first child"; break; 132 case EOpAddAssign: out.debug << "add second child into first child"; break; 133 case EOpSubAssign: out.debug << "subtract second child into first child"; break; 134 case EOpMulAssign: out.debug << "multiply second child into first child"; break; 135 case EOpVectorTimesMatrixAssign: out.debug << "matrix mult second child into first child"; break; 136 case EOpVectorTimesScalarAssign: out.debug << "vector scale second child into first child"; break; 137 case EOpMatrixTimesScalarAssign: out.debug << "matrix scale second child into first child"; break; 138 case EOpMatrixTimesMatrixAssign: out.debug << "matrix mult second child into first child"; break; 139 case EOpDivAssign: out.debug << "divide second child into first child"; break; 140 case EOpModAssign: out.debug << "mod second child into first child"; break; 141 case EOpAndAssign: out.debug << "and second child into first child"; break; 142 case EOpInclusiveOrAssign: out.debug << "or second child into first child"; break; 143 case EOpExclusiveOrAssign: out.debug << "exclusive or second child into first child"; break; 144 case EOpLeftShiftAssign: out.debug << "left shift second child into first child"; break; 145 case EOpRightShiftAssign: out.debug << "right shift second child into first child"; break; 146 147 case EOpIndexDirect: out.debug << "direct index"; break; 148 case EOpIndexIndirect: out.debug << "indirect index"; break; 149 case EOpIndexDirectStruct: 150 out.debug << (*node->getLeft()->getType().getStruct())[node->getRight()->getAsConstantUnion()->getConstArray()[0].getIConst()].type->getFieldName(); 151 out.debug << ": direct index for structure"; break; 152 case EOpVectorSwizzle: out.debug << "vector swizzle"; break; 153 154 case EOpAdd: out.debug << "add"; break; 155 case EOpSub: out.debug << "subtract"; break; 156 case EOpMul: out.debug << "component-wise multiply"; break; 157 case EOpDiv: out.debug << "divide"; break; 158 case EOpMod: out.debug << "mod"; break; 159 case EOpRightShift: out.debug << "right-shift"; break; 160 case EOpLeftShift: out.debug << "left-shift"; break; 161 case EOpAnd: out.debug << "bitwise and"; break; 162 case EOpInclusiveOr: out.debug << "inclusive-or"; break; 163 case EOpExclusiveOr: out.debug << "exclusive-or"; break; 164 case EOpEqual: out.debug << "Compare Equal"; break; 165 case EOpNotEqual: out.debug << "Compare Not Equal"; break; 166 case EOpLessThan: out.debug << "Compare Less Than"; break; 167 case EOpGreaterThan: out.debug << "Compare Greater Than"; break; 168 case EOpLessThanEqual: out.debug << "Compare Less Than or Equal"; break; 169 case EOpGreaterThanEqual: out.debug << "Compare Greater Than or Equal"; break; 170 171 case EOpVectorTimesScalar: out.debug << "vector-scale"; break; 172 case EOpVectorTimesMatrix: out.debug << "vector-times-matrix"; break; 173 case EOpMatrixTimesVector: out.debug << "matrix-times-vector"; break; 174 case EOpMatrixTimesScalar: out.debug << "matrix-scale"; break; 175 case EOpMatrixTimesMatrix: out.debug << "matrix-multiply"; break; 176 177 case EOpLogicalOr: out.debug << "logical-or"; break; 178 case EOpLogicalXor: out.debug << "logical-xor"; break; 179 case EOpLogicalAnd: out.debug << "logical-and"; break; 180 default: out.debug << "<unknown op>"; 181 } 182 183 out.debug << " (" << node->getCompleteString() << ")"; 184 185 out.debug << "\n"; 186 187 return true; 188} 189 190bool TOutputTraverser::visitUnary(TVisit /* visit */, TIntermUnary* node) 191{ 192 TInfoSink& out = infoSink; 193 194 OutputTreeText(out, node, depth); 195 196 switch (node->getOp()) { 197 case EOpNegative: out.debug << "Negate value"; break; 198 case EOpVectorLogicalNot: 199 case EOpLogicalNot: out.debug << "Negate conditional"; break; 200 case EOpBitwiseNot: out.debug << "Bitwise not"; break; 201 202 case EOpPostIncrement: out.debug << "Post-Increment"; break; 203 case EOpPostDecrement: out.debug << "Post-Decrement"; break; 204 case EOpPreIncrement: out.debug << "Pre-Increment"; break; 205 case EOpPreDecrement: out.debug << "Pre-Decrement"; break; 206 207 case EOpConvIntToBool: out.debug << "Convert int to bool"; break; 208 case EOpConvUintToBool: out.debug << "Convert uint to bool"; break; 209 case EOpConvFloatToBool: out.debug << "Convert float to bool"; break; 210 case EOpConvDoubleToBool: out.debug << "Convert double to bool"; break; 211 case EOpConvInt64ToBool: out.debug << "Convert int64 to bool"; break; 212 case EOpConvUint64ToBool: out.debug << "Convert uint64 to bool"; break; 213 case EOpConvIntToFloat: out.debug << "Convert int to float"; break; 214 case EOpConvUintToFloat: out.debug << "Convert uint to float"; break; 215 case EOpConvDoubleToFloat: out.debug << "Convert double to float"; break; 216 case EOpConvInt64ToFloat: out.debug << "Convert int64 to float"; break; 217 case EOpConvUint64ToFloat: out.debug << "Convert uint64 to float"; break; 218 case EOpConvBoolToFloat: out.debug << "Convert bool to float"; break; 219 case EOpConvUintToInt: out.debug << "Convert uint to int"; break; 220 case EOpConvFloatToInt: out.debug << "Convert float to int"; break; 221 case EOpConvDoubleToInt: out.debug << "Convert double to int"; break; 222 case EOpConvBoolToInt: out.debug << "Convert bool to int"; break; 223 case EOpConvInt64ToInt: out.debug << "Convert int64 to int"; break; 224 case EOpConvUint64ToInt: out.debug << "Convert uint64 to int"; break; 225 case EOpConvIntToUint: out.debug << "Convert int to uint"; break; 226 case EOpConvFloatToUint: out.debug << "Convert float to uint"; break; 227 case EOpConvDoubleToUint: out.debug << "Convert double to uint"; break; 228 case EOpConvBoolToUint: out.debug << "Convert bool to uint"; break; 229 case EOpConvInt64ToUint: out.debug << "Convert int64 to uint"; break; 230 case EOpConvUint64ToUint: out.debug << "Convert uint64 to uint"; break; 231 case EOpConvIntToDouble: out.debug << "Convert int to double"; break; 232 case EOpConvUintToDouble: out.debug << "Convert uint to double"; break; 233 case EOpConvFloatToDouble: out.debug << "Convert float to double"; break; 234 case EOpConvBoolToDouble: out.debug << "Convert bool to double"; break; 235 case EOpConvInt64ToDouble: out.debug << "Convert int64 to double"; break; 236 case EOpConvUint64ToDouble: out.debug << "Convert uint64 to double"; break; 237 case EOpConvBoolToInt64: out.debug << "Convert bool to int64"; break; 238 case EOpConvIntToInt64: out.debug << "Convert int to int64"; break; 239 case EOpConvUintToInt64: out.debug << "Convert uint to int64"; break; 240 case EOpConvFloatToInt64: out.debug << "Convert float to int64"; break; 241 case EOpConvDoubleToInt64: out.debug << "Convert double to int64"; break; 242 case EOpConvUint64ToInt64: out.debug << "Convert uint64 to int64"; break; 243 case EOpConvBoolToUint64: out.debug << "Convert bool to uint64"; break; 244 case EOpConvIntToUint64: out.debug << "Convert int to uint64"; break; 245 case EOpConvUintToUint64: out.debug << "Convert uint to uint64"; break; 246 case EOpConvFloatToUint64: out.debug << "Convert float to uint64"; break; 247 case EOpConvDoubleToUint64: out.debug << "Convert double to uint64"; break; 248 case EOpConvInt64ToUint64: out.debug << "Convert uint64 to uint64"; break; 249 250 case EOpRadians: out.debug << "radians"; break; 251 case EOpDegrees: out.debug << "degrees"; break; 252 case EOpSin: out.debug << "sine"; break; 253 case EOpCos: out.debug << "cosine"; break; 254 case EOpTan: out.debug << "tangent"; break; 255 case EOpAsin: out.debug << "arc sine"; break; 256 case EOpAcos: out.debug << "arc cosine"; break; 257 case EOpAtan: out.debug << "arc tangent"; break; 258 case EOpSinh: out.debug << "hyp. sine"; break; 259 case EOpCosh: out.debug << "hyp. cosine"; break; 260 case EOpTanh: out.debug << "hyp. tangent"; break; 261 case EOpAsinh: out.debug << "arc hyp. sine"; break; 262 case EOpAcosh: out.debug << "arc hyp. cosine"; break; 263 case EOpAtanh: out.debug << "arc hyp. tangent"; break; 264 265 case EOpExp: out.debug << "exp"; break; 266 case EOpLog: out.debug << "log"; break; 267 case EOpExp2: out.debug << "exp2"; break; 268 case EOpLog2: out.debug << "log2"; break; 269 case EOpSqrt: out.debug << "sqrt"; break; 270 case EOpInverseSqrt: out.debug << "inverse sqrt"; break; 271 272 case EOpAbs: out.debug << "Absolute value"; break; 273 case EOpSign: out.debug << "Sign"; break; 274 case EOpFloor: out.debug << "Floor"; break; 275 case EOpTrunc: out.debug << "trunc"; break; 276 case EOpRound: out.debug << "round"; break; 277 case EOpRoundEven: out.debug << "roundEven"; break; 278 case EOpCeil: out.debug << "Ceiling"; break; 279 case EOpFract: out.debug << "Fraction"; break; 280 281 case EOpIsNan: out.debug << "isnan"; break; 282 case EOpIsInf: out.debug << "isinf"; break; 283 284 case EOpFloatBitsToInt: out.debug << "floatBitsToInt"; break; 285 case EOpFloatBitsToUint:out.debug << "floatBitsToUint"; break; 286 case EOpIntBitsToFloat: out.debug << "intBitsToFloat"; break; 287 case EOpUintBitsToFloat:out.debug << "uintBitsToFloat"; break; 288 case EOpDoubleBitsToInt64: out.debug << "doubleBitsToInt64"; break; 289 case EOpDoubleBitsToUint64: out.debug << "doubleBitsToUint64"; break; 290 case EOpInt64BitsToDouble: out.debug << "int64BitsToDouble"; break; 291 case EOpUint64BitsToDouble: out.debug << "uint64BitsToDouble"; break; 292 case EOpPackSnorm2x16: out.debug << "packSnorm2x16"; break; 293 case EOpUnpackSnorm2x16:out.debug << "unpackSnorm2x16"; break; 294 case EOpPackUnorm2x16: out.debug << "packUnorm2x16"; break; 295 case EOpUnpackUnorm2x16:out.debug << "unpackUnorm2x16"; break; 296 case EOpPackHalf2x16: out.debug << "packHalf2x16"; break; 297 case EOpUnpackHalf2x16: out.debug << "unpackHalf2x16"; break; 298 299 case EOpPackSnorm4x8: out.debug << "PackSnorm4x8"; break; 300 case EOpUnpackSnorm4x8: out.debug << "UnpackSnorm4x8"; break; 301 case EOpPackUnorm4x8: out.debug << "PackUnorm4x8"; break; 302 case EOpUnpackUnorm4x8: out.debug << "UnpackUnorm4x8"; break; 303 case EOpPackDouble2x32: out.debug << "PackDouble2x32"; break; 304 case EOpUnpackDouble2x32: out.debug << "UnpackDouble2x32"; break; 305 306 case EOpPackInt2x32: out.debug << "packInt2x32"; break; 307 case EOpUnpackInt2x32: out.debug << "unpackInt2x32"; break; 308 case EOpPackUint2x32: out.debug << "packUint2x32"; break; 309 case EOpUnpackUint2x32: out.debug << "unpackUint2x32"; break; 310 311 case EOpLength: out.debug << "length"; break; 312 case EOpNormalize: out.debug << "normalize"; break; 313 case EOpDPdx: out.debug << "dPdx"; break; 314 case EOpDPdy: out.debug << "dPdy"; break; 315 case EOpFwidth: out.debug << "fwidth"; break; 316 case EOpDPdxFine: out.debug << "dPdxFine"; break; 317 case EOpDPdyFine: out.debug << "dPdyFine"; break; 318 case EOpFwidthFine: out.debug << "fwidthFine"; break; 319 case EOpDPdxCoarse: out.debug << "dPdxCoarse"; break; 320 case EOpDPdyCoarse: out.debug << "dPdyCoarse"; break; 321 case EOpFwidthCoarse: out.debug << "fwidthCoarse"; break; 322 323 case EOpInterpolateAtCentroid: out.debug << "interpolateAtCentroid"; break; 324 325 case EOpDeterminant: out.debug << "determinant"; break; 326 case EOpMatrixInverse: out.debug << "inverse"; break; 327 case EOpTranspose: out.debug << "transpose"; break; 328 329 case EOpAny: out.debug << "any"; break; 330 case EOpAll: out.debug << "all"; break; 331 332 case EOpArrayLength: out.debug << "array length"; break; 333 334 case EOpEmitStreamVertex: out.debug << "EmitStreamVertex"; break; 335 case EOpEndStreamPrimitive: out.debug << "EndStreamPrimitive"; break; 336 337 case EOpAtomicCounterIncrement: out.debug << "AtomicCounterIncrement";break; 338 case EOpAtomicCounterDecrement: out.debug << "AtomicCounterDecrement";break; 339 case EOpAtomicCounter: out.debug << "AtomicCounter"; break; 340 341 case EOpTextureQuerySize: out.debug << "textureSize"; break; 342 case EOpTextureQueryLod: out.debug << "textureQueryLod"; break; 343 case EOpTextureQueryLevels: out.debug << "textureQueryLevels"; break; 344 case EOpTextureQuerySamples: out.debug << "textureSamples"; break; 345 case EOpImageQuerySize: out.debug << "imageQuerySize"; break; 346 case EOpImageQuerySamples: out.debug << "imageQuerySamples"; break; 347 case EOpImageLoad: out.debug << "imageLoad"; break; 348 349 case EOpBitFieldReverse: out.debug << "bitFieldReverse"; break; 350 case EOpBitCount: out.debug << "bitCount"; break; 351 case EOpFindLSB: out.debug << "findLSB"; break; 352 case EOpFindMSB: out.debug << "findMSB"; break; 353 354 case EOpNoise: out.debug << "noise"; break; 355 356 case EOpBallot: out.debug << "ballot"; break; 357 case EOpReadFirstInvocation: out.debug << "readFirstInvocation"; break; 358 case EOpAnyInvocation: out.debug << "anyInvocation"; break; 359 case EOpAllInvocations: out.debug << "allInvocations"; break; 360 case EOpAllInvocationsEqual: out.debug << "allInvocationsEqual"; break; 361 362 case EOpClip: out.debug << "clip"; break; 363 case EOpIsFinite: out.debug << "isfinite"; break; 364 case EOpLog10: out.debug << "log10"; break; 365 case EOpRcp: out.debug << "rcp"; break; 366 case EOpSaturate: out.debug << "saturate"; break; 367 368 default: out.debug.message(EPrefixError, "Bad unary op"); 369 } 370 371 out.debug << " (" << node->getCompleteString() << ")"; 372 373 out.debug << "\n"; 374 375 return true; 376} 377 378bool TOutputTraverser::visitAggregate(TVisit /* visit */, TIntermAggregate* node) 379{ 380 TInfoSink& out = infoSink; 381 382 if (node->getOp() == EOpNull) { 383 out.debug.message(EPrefixError, "node is still EOpNull!"); 384 return true; 385 } 386 387 OutputTreeText(out, node, depth); 388 389 switch (node->getOp()) { 390 case EOpSequence: out.debug << "Sequence\n"; return true; 391 case EOpLinkerObjects: out.debug << "Linker Objects\n"; return true; 392 case EOpComma: out.debug << "Comma"; break; 393 case EOpFunction: out.debug << "Function Definition: " << node->getName(); break; 394 case EOpFunctionCall: out.debug << "Function Call: " << node->getName(); break; 395 case EOpParameters: out.debug << "Function Parameters: "; break; 396 397 case EOpConstructFloat: out.debug << "Construct float"; break; 398 case EOpConstructDouble:out.debug << "Construct double"; break; 399 case EOpConstructVec2: out.debug << "Construct vec2"; break; 400 case EOpConstructVec3: out.debug << "Construct vec3"; break; 401 case EOpConstructVec4: out.debug << "Construct vec4"; break; 402 case EOpConstructBool: out.debug << "Construct bool"; break; 403 case EOpConstructBVec2: out.debug << "Construct bvec2"; break; 404 case EOpConstructBVec3: out.debug << "Construct bvec3"; break; 405 case EOpConstructBVec4: out.debug << "Construct bvec4"; break; 406 case EOpConstructInt: out.debug << "Construct int"; break; 407 case EOpConstructIVec2: out.debug << "Construct ivec2"; break; 408 case EOpConstructIVec3: out.debug << "Construct ivec3"; break; 409 case EOpConstructIVec4: out.debug << "Construct ivec4"; break; 410 case EOpConstructUint: out.debug << "Construct uint"; break; 411 case EOpConstructUVec2: out.debug << "Construct uvec2"; break; 412 case EOpConstructUVec3: out.debug << "Construct uvec3"; break; 413 case EOpConstructUVec4: out.debug << "Construct uvec4"; break; 414 case EOpConstructInt64: out.debug << "Construct int64_t"; break; 415 case EOpConstructI64Vec2: out.debug << "Construct i64vec2"; break; 416 case EOpConstructI64Vec3: out.debug << "Construct i64vec3"; break; 417 case EOpConstructI64Vec4: out.debug << "Construct i64vec4"; break; 418 case EOpConstructUint64: out.debug << "Construct uint64_t"; break; 419 case EOpConstructU64Vec2: out.debug << "Construct u64vec2"; break; 420 case EOpConstructU64Vec3: out.debug << "Construct u64vec3"; break; 421 case EOpConstructU64Vec4: out.debug << "Construct u64vec4"; break; 422 case EOpConstructMat2x2: out.debug << "Construct mat2"; break; 423 case EOpConstructMat2x3: out.debug << "Construct mat2x3"; break; 424 case EOpConstructMat2x4: out.debug << "Construct mat2x4"; break; 425 case EOpConstructMat3x2: out.debug << "Construct mat3x2"; break; 426 case EOpConstructMat3x3: out.debug << "Construct mat3"; break; 427 case EOpConstructMat3x4: out.debug << "Construct mat3x4"; break; 428 case EOpConstructMat4x2: out.debug << "Construct mat4x2"; break; 429 case EOpConstructMat4x3: out.debug << "Construct mat4x3"; break; 430 case EOpConstructMat4x4: out.debug << "Construct mat4"; break; 431 case EOpConstructDMat2x2: out.debug << "Construct dmat2"; break; 432 case EOpConstructDMat2x3: out.debug << "Construct dmat2x3"; break; 433 case EOpConstructDMat2x4: out.debug << "Construct dmat2x4"; break; 434 case EOpConstructDMat3x2: out.debug << "Construct dmat3x2"; break; 435 case EOpConstructDMat3x3: out.debug << "Construct dmat3"; break; 436 case EOpConstructDMat3x4: out.debug << "Construct dmat3x4"; break; 437 case EOpConstructDMat4x2: out.debug << "Construct dmat4x2"; break; 438 case EOpConstructDMat4x3: out.debug << "Construct dmat4x3"; break; 439 case EOpConstructDMat4x4: out.debug << "Construct dmat4"; break; 440 case EOpConstructStruct: out.debug << "Construct structure"; break; 441 case EOpConstructTextureSampler: out.debug << "Construct combined texture-sampler"; break; 442 443 case EOpLessThan: out.debug << "Compare Less Than"; break; 444 case EOpGreaterThan: out.debug << "Compare Greater Than"; break; 445 case EOpLessThanEqual: out.debug << "Compare Less Than or Equal"; break; 446 case EOpGreaterThanEqual: out.debug << "Compare Greater Than or Equal"; break; 447 case EOpVectorEqual: out.debug << "Equal"; break; 448 case EOpVectorNotEqual: out.debug << "NotEqual"; break; 449 450 case EOpMod: out.debug << "mod"; break; 451 case EOpModf: out.debug << "modf"; break; 452 case EOpPow: out.debug << "pow"; break; 453 454 case EOpAtan: out.debug << "arc tangent"; break; 455 456 case EOpMin: out.debug << "min"; break; 457 case EOpMax: out.debug << "max"; break; 458 case EOpClamp: out.debug << "clamp"; break; 459 case EOpMix: out.debug << "mix"; break; 460 case EOpStep: out.debug << "step"; break; 461 case EOpSmoothStep: out.debug << "smoothstep"; break; 462 463 case EOpDistance: out.debug << "distance"; break; 464 case EOpDot: out.debug << "dot-product"; break; 465 case EOpCross: out.debug << "cross-product"; break; 466 case EOpFaceForward: out.debug << "face-forward"; break; 467 case EOpReflect: out.debug << "reflect"; break; 468 case EOpRefract: out.debug << "refract"; break; 469 case EOpMul: out.debug << "component-wise multiply"; break; 470 case EOpOuterProduct: out.debug << "outer product"; break; 471 472 case EOpEmitVertex: out.debug << "EmitVertex"; break; 473 case EOpEndPrimitive: out.debug << "EndPrimitive"; break; 474 475 case EOpBarrier: out.debug << "Barrier"; break; 476 case EOpMemoryBarrier: out.debug << "MemoryBarrier"; break; 477 case EOpMemoryBarrierAtomicCounter: out.debug << "MemoryBarrierAtomicCounter"; break; 478 case EOpMemoryBarrierBuffer: out.debug << "MemoryBarrierBuffer"; break; 479 case EOpMemoryBarrierImage: out.debug << "MemoryBarrierImage"; break; 480 case EOpMemoryBarrierShared: out.debug << "MemoryBarrierShared"; break; 481 case EOpGroupMemoryBarrier: out.debug << "GroupMemoryBarrier"; break; 482 483 case EOpReadInvocation: out.debug << "readInvocation"; break; 484 485 case EOpAtomicAdd: out.debug << "AtomicAdd"; break; 486 case EOpAtomicMin: out.debug << "AtomicMin"; break; 487 case EOpAtomicMax: out.debug << "AtomicMax"; break; 488 case EOpAtomicAnd: out.debug << "AtomicAnd"; break; 489 case EOpAtomicOr: out.debug << "AtomicOr"; break; 490 case EOpAtomicXor: out.debug << "AtomicXor"; break; 491 case EOpAtomicExchange: out.debug << "AtomicExchange"; break; 492 case EOpAtomicCompSwap: out.debug << "AtomicCompSwap"; break; 493 494 case EOpImageQuerySize: out.debug << "imageQuerySize"; break; 495 case EOpImageQuerySamples: out.debug << "imageQuerySamples"; break; 496 case EOpImageLoad: out.debug << "imageLoad"; break; 497 case EOpImageStore: out.debug << "imageStore"; break; 498 case EOpImageAtomicAdd: out.debug << "imageAtomicAdd"; break; 499 case EOpImageAtomicMin: out.debug << "imageAtomicMin"; break; 500 case EOpImageAtomicMax: out.debug << "imageAtomicMax"; break; 501 case EOpImageAtomicAnd: out.debug << "imageAtomicAnd"; break; 502 case EOpImageAtomicOr: out.debug << "imageAtomicOr"; break; 503 case EOpImageAtomicXor: out.debug << "imageAtomicXor"; break; 504 case EOpImageAtomicExchange: out.debug << "imageAtomicExchange"; break; 505 case EOpImageAtomicCompSwap: out.debug << "imageAtomicCompSwap"; break; 506 507 case EOpTextureQuerySize: out.debug << "textureSize"; break; 508 case EOpTextureQueryLod: out.debug << "textureQueryLod"; break; 509 case EOpTextureQueryLevels: out.debug << "textureQueryLevels"; break; 510 case EOpTextureQuerySamples: out.debug << "textureSamples"; break; 511 case EOpTexture: out.debug << "texture"; break; 512 case EOpTextureProj: out.debug << "textureProj"; break; 513 case EOpTextureLod: out.debug << "textureLod"; break; 514 case EOpTextureOffset: out.debug << "textureOffset"; break; 515 case EOpTextureFetch: out.debug << "textureFetch"; break; 516 case EOpTextureFetchOffset: out.debug << "textureFetchOffset"; break; 517 case EOpTextureProjOffset: out.debug << "textureProjOffset"; break; 518 case EOpTextureLodOffset: out.debug << "textureLodOffset"; break; 519 case EOpTextureProjLod: out.debug << "textureProjLod"; break; 520 case EOpTextureProjLodOffset: out.debug << "textureProjLodOffset"; break; 521 case EOpTextureGrad: out.debug << "textureGrad"; break; 522 case EOpTextureGradOffset: out.debug << "textureGradOffset"; break; 523 case EOpTextureProjGrad: out.debug << "textureProjGrad"; break; 524 case EOpTextureProjGradOffset: out.debug << "textureProjGradOffset"; break; 525 case EOpTextureGather: out.debug << "textureGather"; break; 526 case EOpTextureGatherOffset: out.debug << "textureGatherOffset"; break; 527 case EOpTextureGatherOffsets: out.debug << "textureGatherOffsets"; break; 528 529 case EOpAddCarry: out.debug << "addCarry"; break; 530 case EOpSubBorrow: out.debug << "subBorrow"; break; 531 case EOpUMulExtended: out.debug << "uMulExtended"; break; 532 case EOpIMulExtended: out.debug << "iMulExtended"; break; 533 case EOpBitfieldExtract: out.debug << "bitfieldExtract"; break; 534 case EOpBitfieldInsert: out.debug << "bitfieldInsert"; break; 535 536 case EOpFma: out.debug << "fma"; break; 537 case EOpFrexp: out.debug << "frexp"; break; 538 case EOpLdexp: out.debug << "ldexp"; break; 539 540 case EOpInterpolateAtSample: out.debug << "interpolateAtSample"; break; 541 case EOpInterpolateAtOffset: out.debug << "interpolateAtOffset"; break; 542 543 case EOpSinCos: out.debug << "sincos"; break; 544 case EOpGenMul: out.debug << "mul"; break; 545 546 case EOpAllMemoryBarrierWithGroupSync: out.debug << "AllMemoryBarrierWithGroupSync"; break; 547 case EOpGroupMemoryBarrierWithGroupSync: out.debug << "GroupMemoryBarrierWithGroupSync"; break; 548 case EOpWorkgroupMemoryBarrier: out.debug << "WorkgroupMemoryBarrier"; break; 549 case EOpWorkgroupMemoryBarrierWithGroupSync: out.debug << "WorkgroupMemoryBarrierWithGroupSync"; break; 550 551 default: out.debug.message(EPrefixError, "Bad aggregation op"); 552 } 553 554 if (node->getOp() != EOpSequence && node->getOp() != EOpParameters) 555 out.debug << " (" << node->getCompleteString() << ")"; 556 557 out.debug << "\n"; 558 559 return true; 560} 561 562bool TOutputTraverser::visitSelection(TVisit /* visit */, TIntermSelection* node) 563{ 564 TInfoSink& out = infoSink; 565 566 OutputTreeText(out, node, depth); 567 568 out.debug << "Test condition and select"; 569 out.debug << " (" << node->getCompleteString() << ")\n"; 570 571 ++depth; 572 573 OutputTreeText(out, node, depth); 574 out.debug << "Condition\n"; 575 node->getCondition()->traverse(this); 576 577 OutputTreeText(out, node, depth); 578 if (node->getTrueBlock()) { 579 out.debug << "true case\n"; 580 node->getTrueBlock()->traverse(this); 581 } else 582 out.debug << "true case is null\n"; 583 584 if (node->getFalseBlock()) { 585 OutputTreeText(out, node, depth); 586 out.debug << "false case\n"; 587 node->getFalseBlock()->traverse(this); 588 } 589 590 --depth; 591 592 return false; 593} 594 595static void OutputConstantUnion(TInfoSink& out, const TIntermTyped* node, const TConstUnionArray& constUnion, int depth) 596{ 597 int size = node->getType().computeNumComponents(); 598 599 for (int i = 0; i < size; i++) { 600 OutputTreeText(out, node, depth); 601 switch (constUnion[i].getType()) { 602 case EbtBool: 603 if (constUnion[i].getBConst()) 604 out.debug << "true"; 605 else 606 out.debug << "false"; 607 608 out.debug << " (" << "const bool" << ")"; 609 610 out.debug << "\n"; 611 break; 612 case EbtFloat: 613 case EbtDouble: 614 { 615 const double value = constUnion[i].getDConst(); 616 // Print infinity in a portable way, for test stability. 617 // Other cases may be needed in the future: negative infinity, 618 // and NaNs. 619 if (is_positive_infinity(value)) 620 out.debug << "inf\n"; 621 else { 622 const int maxSize = 300; 623 char buf[maxSize]; 624 snprintf(buf, maxSize, "%f", value); 625 626 out.debug << buf << "\n"; 627 } 628 } 629 break; 630 case EbtInt: 631 { 632 const int maxSize = 300; 633 char buf[maxSize]; 634 snprintf(buf, maxSize, "%d (%s)", constUnion[i].getIConst(), "const int"); 635 636 out.debug << buf << "\n"; 637 } 638 break; 639 case EbtUint: 640 { 641 const int maxSize = 300; 642 char buf[maxSize]; 643 snprintf(buf, maxSize, "%u (%s)", constUnion[i].getUConst(), "const uint"); 644 645 out.debug << buf << "\n"; 646 } 647 break; 648 case EbtInt64: 649 { 650 const int maxSize = 300; 651 char buf[maxSize]; 652 snprintf(buf, maxSize, "%lld (%s)", constUnion[i].getI64Const(), "const int64_t"); 653 654 out.debug << buf << "\n"; 655 } 656 break; 657 case EbtUint64: 658 { 659 const int maxSize = 300; 660 char buf[maxSize]; 661 snprintf(buf, maxSize, "%llu (%s)", constUnion[i].getU64Const(), "const uint64_t"); 662 663 out.debug << buf << "\n"; 664 } 665 break; 666 default: 667 out.info.message(EPrefixInternalError, "Unknown constant", node->getLoc()); 668 break; 669 } 670 } 671} 672 673void TOutputTraverser::visitConstantUnion(TIntermConstantUnion* node) 674{ 675 OutputTreeText(infoSink, node, depth); 676 infoSink.debug << "Constant:\n"; 677 678 OutputConstantUnion(infoSink, node, node->getConstArray(), depth + 1); 679} 680 681void TOutputTraverser::visitSymbol(TIntermSymbol* node) 682{ 683 OutputTreeText(infoSink, node, depth); 684 685 infoSink.debug << "'" << node->getName() << "' (" << node->getCompleteString() << ")\n"; 686 687 if (! node->getConstArray().empty()) 688 OutputConstantUnion(infoSink, node, node->getConstArray(), depth + 1); 689 else if (node->getConstSubtree()) { 690 incrementDepth(node); 691 node->getConstSubtree()->traverse(this); 692 decrementDepth(); 693 } 694} 695 696bool TOutputTraverser::visitLoop(TVisit /* visit */, TIntermLoop* node) 697{ 698 TInfoSink& out = infoSink; 699 700 OutputTreeText(out, node, depth); 701 702 out.debug << "Loop with condition "; 703 if (! node->testFirst()) 704 out.debug << "not "; 705 out.debug << "tested first\n"; 706 707 ++depth; 708 709 OutputTreeText(infoSink, node, depth); 710 if (node->getTest()) { 711 out.debug << "Loop Condition\n"; 712 node->getTest()->traverse(this); 713 } else 714 out.debug << "No loop condition\n"; 715 716 OutputTreeText(infoSink, node, depth); 717 if (node->getBody()) { 718 out.debug << "Loop Body\n"; 719 node->getBody()->traverse(this); 720 } else 721 out.debug << "No loop body\n"; 722 723 if (node->getTerminal()) { 724 OutputTreeText(infoSink, node, depth); 725 out.debug << "Loop Terminal Expression\n"; 726 node->getTerminal()->traverse(this); 727 } 728 729 --depth; 730 731 return false; 732} 733 734bool TOutputTraverser::visitBranch(TVisit /* visit*/, TIntermBranch* node) 735{ 736 TInfoSink& out = infoSink; 737 738 OutputTreeText(out, node, depth); 739 740 switch (node->getFlowOp()) { 741 case EOpKill: out.debug << "Branch: Kill"; break; 742 case EOpBreak: out.debug << "Branch: Break"; break; 743 case EOpContinue: out.debug << "Branch: Continue"; break; 744 case EOpReturn: out.debug << "Branch: Return"; break; 745 case EOpCase: out.debug << "case: "; break; 746 case EOpDefault: out.debug << "default: "; break; 747 default: out.debug << "Branch: Unknown Branch"; break; 748 } 749 750 if (node->getExpression()) { 751 out.debug << " with expression\n"; 752 ++depth; 753 node->getExpression()->traverse(this); 754 --depth; 755 } else 756 out.debug << "\n"; 757 758 return false; 759} 760 761bool TOutputTraverser::visitSwitch(TVisit /* visit */, TIntermSwitch* node) 762{ 763 TInfoSink& out = infoSink; 764 765 OutputTreeText(out, node, depth); 766 out.debug << "switch\n"; 767 768 OutputTreeText(out, node, depth); 769 out.debug << "condition\n"; 770 ++depth; 771 node->getCondition()->traverse(this); 772 773 --depth; 774 OutputTreeText(out, node, depth); 775 out.debug << "body\n"; 776 ++depth; 777 node->getBody()->traverse(this); 778 779 --depth; 780 781 return false; 782} 783 784// 785// This function is the one to call externally to start the traversal. 786// Individual functions can be initialized to 0 to skip processing of that 787// type of node. It's children will still be processed. 788// 789void TIntermediate::output(TInfoSink& infoSink, bool tree) 790{ 791 infoSink.debug << "Shader version: " << version << "\n"; 792 if (requestedExtensions.size() > 0) { 793 for (auto extIt = requestedExtensions.begin(); extIt != requestedExtensions.end(); ++extIt) 794 infoSink.debug << "Requested " << *extIt << "\n"; 795 } 796 797 if (xfbMode) 798 infoSink.debug << "in xfb mode\n"; 799 800 switch (language) { 801 case EShLangVertex: 802 break; 803 804 case EShLangTessControl: 805 infoSink.debug << "vertices = " << vertices << "\n"; 806 break; 807 808 case EShLangTessEvaluation: 809 infoSink.debug << "input primitive = " << TQualifier::getGeometryString(inputPrimitive) << "\n"; 810 infoSink.debug << "vertex spacing = " << TQualifier::getVertexSpacingString(vertexSpacing) << "\n"; 811 infoSink.debug << "triangle order = " << TQualifier::getVertexOrderString(vertexOrder) << "\n"; 812 if (pointMode) 813 infoSink.debug << "using point mode\n"; 814 break; 815 816 case EShLangGeometry: 817 infoSink.debug << "invocations = " << invocations << "\n"; 818 infoSink.debug << "max_vertices = " << vertices << "\n"; 819 infoSink.debug << "input primitive = " << TQualifier::getGeometryString(inputPrimitive) << "\n"; 820 infoSink.debug << "output primitive = " << TQualifier::getGeometryString(outputPrimitive) << "\n"; 821 break; 822 823 case EShLangFragment: 824 if (pixelCenterInteger) 825 infoSink.debug << "gl_FragCoord pixel center is integer\n"; 826 if (originUpperLeft) 827 infoSink.debug << "gl_FragCoord origin is upper left\n"; 828 if (earlyFragmentTests) 829 infoSink.debug << "using early_fragment_tests\n"; 830 if (depthLayout != EldNone) 831 infoSink.debug << "using " << TQualifier::getLayoutDepthString(depthLayout) << "\n"; 832 if (blendEquations != 0) { 833 infoSink.debug << "using"; 834 // blendEquations is a mask, decode it 835 for (TBlendEquationShift be = (TBlendEquationShift)0; be < EBlendCount; be = (TBlendEquationShift)(be + 1)) { 836 if (blendEquations & (1 << be)) 837 infoSink.debug << " " << TQualifier::getBlendEquationString(be); 838 } 839 infoSink.debug << "\n"; 840 } 841 break; 842 843 case EShLangCompute: 844 infoSink.debug << "local_size = (" << localSize[0] << ", " << localSize[1] << ", " << localSize[2] << ")\n"; 845 { 846 if (localSizeSpecId[0] != TQualifier::layoutNotSet || 847 localSizeSpecId[1] != TQualifier::layoutNotSet || 848 localSizeSpecId[2] != TQualifier::layoutNotSet) { 849 infoSink.debug << "local_size ids = (" << 850 localSizeSpecId[0] << ", " << 851 localSizeSpecId[1] << ", " << 852 localSizeSpecId[2] << ")\n"; 853 } 854 } 855 break; 856 857 default: 858 break; 859 } 860 861 if (treeRoot == 0 || ! tree) 862 return; 863 864 TOutputTraverser it(infoSink); 865 866 treeRoot->traverse(&it); 867} 868 869} // end namespace glslang 870