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 // 8 // Definition of the in-memory high-level intermediate representation 9 // of shaders. This is a tree that parser creates. 10 // 11 // Nodes in the tree are defined as a hierarchy of classes derived from 12 // TIntermNode. Each is a node in a tree. There is no preset branching factor; 13 // each node can have it's own type of list of children. 14 // 15 16 #ifndef __INTERMEDIATE_H 17 #define __INTERMEDIATE_H 18 19 #include "GLSLANG/ShaderLang.h" 20 21 #include <algorithm> 22 #include "compiler/Common.h" 23 #include "compiler/Types.h" 24 #include "compiler/ConstantUnion.h" 25 26 // 27 // Operators used by the high-level (parse tree) representation. 28 // 29 enum TOperator { 30 EOpNull, // if in a node, should only mean a node is still being built 31 EOpSequence, // denotes a list of statements, or parameters, etc. 32 EOpFunctionCall, 33 EOpFunction, // For function definition 34 EOpParameters, // an aggregate listing the parameters to a function 35 36 EOpDeclaration, 37 EOpPrototype, 38 39 // 40 // Unary operators 41 // 42 43 EOpNegative, 44 EOpLogicalNot, 45 EOpVectorLogicalNot, 46 47 EOpPostIncrement, 48 EOpPostDecrement, 49 EOpPreIncrement, 50 EOpPreDecrement, 51 52 EOpConvIntToBool, 53 EOpConvFloatToBool, 54 EOpConvBoolToFloat, 55 EOpConvIntToFloat, 56 EOpConvFloatToInt, 57 EOpConvBoolToInt, 58 59 // 60 // binary operations 61 // 62 63 EOpAdd, 64 EOpSub, 65 EOpMul, 66 EOpDiv, 67 EOpEqual, 68 EOpNotEqual, 69 EOpVectorEqual, 70 EOpVectorNotEqual, 71 EOpLessThan, 72 EOpGreaterThan, 73 EOpLessThanEqual, 74 EOpGreaterThanEqual, 75 EOpComma, 76 77 EOpVectorTimesScalar, 78 EOpVectorTimesMatrix, 79 EOpMatrixTimesVector, 80 EOpMatrixTimesScalar, 81 82 EOpLogicalOr, 83 EOpLogicalXor, 84 EOpLogicalAnd, 85 86 EOpIndexDirect, 87 EOpIndexIndirect, 88 EOpIndexDirectStruct, 89 90 EOpVectorSwizzle, 91 92 // 93 // Built-in functions potentially mapped to operators 94 // 95 96 EOpRadians, 97 EOpDegrees, 98 EOpSin, 99 EOpCos, 100 EOpTan, 101 EOpAsin, 102 EOpAcos, 103 EOpAtan, 104 105 EOpPow, 106 EOpExp, 107 EOpLog, 108 EOpExp2, 109 EOpLog2, 110 EOpSqrt, 111 EOpInverseSqrt, 112 113 EOpAbs, 114 EOpSign, 115 EOpFloor, 116 EOpCeil, 117 EOpFract, 118 EOpMod, 119 EOpMin, 120 EOpMax, 121 EOpClamp, 122 EOpMix, 123 EOpStep, 124 EOpSmoothStep, 125 126 EOpLength, 127 EOpDistance, 128 EOpDot, 129 EOpCross, 130 EOpNormalize, 131 EOpFaceForward, 132 EOpReflect, 133 EOpRefract, 134 135 EOpDFdx, // Fragment only, OES_standard_derivatives extension 136 EOpDFdy, // Fragment only, OES_standard_derivatives extension 137 EOpFwidth, // Fragment only, OES_standard_derivatives extension 138 139 EOpMatrixTimesMatrix, 140 141 EOpAny, 142 EOpAll, 143 144 // 145 // Branch 146 // 147 148 EOpKill, // Fragment only 149 EOpReturn, 150 EOpBreak, 151 EOpContinue, 152 153 // 154 // Constructors 155 // 156 157 EOpConstructInt, 158 EOpConstructBool, 159 EOpConstructFloat, 160 EOpConstructVec2, 161 EOpConstructVec3, 162 EOpConstructVec4, 163 EOpConstructBVec2, 164 EOpConstructBVec3, 165 EOpConstructBVec4, 166 EOpConstructIVec2, 167 EOpConstructIVec3, 168 EOpConstructIVec4, 169 EOpConstructMat2, 170 EOpConstructMat3, 171 EOpConstructMat4, 172 EOpConstructStruct, 173 174 // 175 // moves 176 // 177 178 EOpAssign, 179 EOpInitialize, 180 EOpAddAssign, 181 EOpSubAssign, 182 EOpMulAssign, 183 EOpVectorTimesMatrixAssign, 184 EOpVectorTimesScalarAssign, 185 EOpMatrixTimesScalarAssign, 186 EOpMatrixTimesMatrixAssign, 187 EOpDivAssign 188 }; 189 190 extern const char* getOperatorString(TOperator op); 191 192 class TIntermTraverser; 193 class TIntermAggregate; 194 class TIntermBinary; 195 class TIntermUnary; 196 class TIntermConstantUnion; 197 class TIntermSelection; 198 class TIntermTyped; 199 class TIntermSymbol; 200 class TIntermLoop; 201 class TInfoSink; 202 203 // 204 // Base class for the tree nodes 205 // 206 class TIntermNode { 207 public: 208 POOL_ALLOCATOR_NEW_DELETE(); 209 TIntermNode() { 210 // TODO: Move this to TSourceLoc constructor 211 // after getting rid of TPublicType. 212 line.first_file = line.last_file = 0; 213 line.first_line = line.last_line = 0; 214 } 215 virtual ~TIntermNode() { } 216 217 const TSourceLoc& getLine() const { return line; } 218 void setLine(const TSourceLoc& l) { line = l; } 219 220 virtual void traverse(TIntermTraverser*) = 0; 221 virtual TIntermTyped* getAsTyped() { return 0; } 222 virtual TIntermConstantUnion* getAsConstantUnion() { return 0; } 223 virtual TIntermAggregate* getAsAggregate() { return 0; } 224 virtual TIntermBinary* getAsBinaryNode() { return 0; } 225 virtual TIntermUnary* getAsUnaryNode() { return 0; } 226 virtual TIntermSelection* getAsSelectionNode() { return 0; } 227 virtual TIntermSymbol* getAsSymbolNode() { return 0; } 228 virtual TIntermLoop* getAsLoopNode() { return 0; } 229 230 protected: 231 TSourceLoc line; 232 }; 233 234 // 235 // This is just to help yacc. 236 // 237 struct TIntermNodePair { 238 TIntermNode* node1; 239 TIntermNode* node2; 240 }; 241 242 // 243 // Intermediate class for nodes that have a type. 244 // 245 class TIntermTyped : public TIntermNode { 246 public: 247 TIntermTyped(const TType& t) : type(t) { } 248 virtual TIntermTyped* getAsTyped() { return this; } 249 250 void setType(const TType& t) { type = t; } 251 const TType& getType() const { return type; } 252 TType* getTypePointer() { return &type; } 253 254 TBasicType getBasicType() const { return type.getBasicType(); } 255 TQualifier getQualifier() const { return type.getQualifier(); } 256 TPrecision getPrecision() const { return type.getPrecision(); } 257 int getNominalSize() const { return type.getNominalSize(); } 258 259 bool isMatrix() const { return type.isMatrix(); } 260 bool isArray() const { return type.isArray(); } 261 bool isVector() const { return type.isVector(); } 262 bool isScalar() const { return type.isScalar(); } 263 const char* getBasicString() const { return type.getBasicString(); } 264 const char* getQualifierString() const { return type.getQualifierString(); } 265 TString getCompleteString() const { return type.getCompleteString(); } 266 267 int totalRegisterCount() const { return type.totalRegisterCount(); } 268 int elementRegisterCount() const { return type.elementRegisterCount(); } 269 int getArraySize() const { return type.getArraySize(); } 270 271 protected: 272 TType type; 273 }; 274 275 // 276 // Handle for, do-while, and while loops. 277 // 278 enum TLoopType { 279 ELoopFor, 280 ELoopWhile, 281 ELoopDoWhile 282 }; 283 284 class TIntermLoop : public TIntermNode { 285 public: 286 TIntermLoop(TLoopType aType, 287 TIntermNode *aInit, TIntermTyped* aCond, TIntermTyped* aExpr, 288 TIntermNode* aBody) : 289 type(aType), 290 init(aInit), 291 cond(aCond), 292 expr(aExpr), 293 body(aBody), 294 unrollFlag(false) { } 295 296 virtual TIntermLoop* getAsLoopNode() { return this; } 297 virtual void traverse(TIntermTraverser*); 298 299 TLoopType getType() const { return type; } 300 TIntermNode* getInit() { return init; } 301 TIntermTyped* getCondition() { return cond; } 302 TIntermTyped* getExpression() { return expr; } 303 TIntermNode* getBody() { return body; } 304 305 void setUnrollFlag(bool flag) { unrollFlag = flag; } 306 bool getUnrollFlag() { return unrollFlag; } 307 308 protected: 309 TLoopType type; 310 TIntermNode* init; // for-loop initialization 311 TIntermTyped* cond; // loop exit condition 312 TIntermTyped* expr; // for-loop expression 313 TIntermNode* body; // loop body 314 315 bool unrollFlag; // Whether the loop should be unrolled or not. 316 }; 317 318 // 319 // Handle break, continue, return, and kill. 320 // 321 class TIntermBranch : public TIntermNode { 322 public: 323 TIntermBranch(TOperator op, TIntermTyped* e) : 324 flowOp(op), 325 expression(e) { } 326 327 virtual void traverse(TIntermTraverser*); 328 329 TOperator getFlowOp() { return flowOp; } 330 TIntermTyped* getExpression() { return expression; } 331 332 protected: 333 TOperator flowOp; 334 TIntermTyped* expression; // non-zero except for "return exp;" statements 335 }; 336 337 // 338 // Nodes that correspond to symbols or constants in the source code. 339 // 340 class TIntermSymbol : public TIntermTyped { 341 public: 342 // if symbol is initialized as symbol(sym), the memory comes from the poolallocator of sym. If sym comes from 343 // per process globalpoolallocator, then it causes increased memory usage per compile 344 // it is essential to use "symbol = sym" to assign to symbol 345 TIntermSymbol(int i, const TString& sym, const TType& t) : 346 TIntermTyped(t), id(i) { symbol = sym; originalSymbol = sym; } 347 348 int getId() const { return id; } 349 const TString& getSymbol() const { return symbol; } 350 351 void setId(int newId) { id = newId; } 352 void setSymbol(const TString& sym) { symbol = sym; } 353 354 const TString& getOriginalSymbol() const { return originalSymbol; } 355 356 virtual void traverse(TIntermTraverser*); 357 virtual TIntermSymbol* getAsSymbolNode() { return this; } 358 359 protected: 360 int id; 361 TString symbol; 362 TString originalSymbol; 363 }; 364 365 class TIntermConstantUnion : public TIntermTyped { 366 public: 367 TIntermConstantUnion(ConstantUnion *unionPointer, const TType& t) : TIntermTyped(t), unionArrayPointer(unionPointer) { } 368 369 ConstantUnion* getUnionArrayPointer() const { return unionArrayPointer; } 370 371 int getIConst(int index) const { return unionArrayPointer ? unionArrayPointer[index].getIConst() : 0; } 372 float getFConst(int index) const { return unionArrayPointer ? unionArrayPointer[index].getFConst() : 0.0f; } 373 bool getBConst(int index) const { return unionArrayPointer ? unionArrayPointer[index].getBConst() : false; } 374 375 virtual TIntermConstantUnion* getAsConstantUnion() { return this; } 376 virtual void traverse(TIntermTraverser*); 377 378 TIntermTyped* fold(TOperator, TIntermTyped*, TInfoSink&); 379 380 protected: 381 ConstantUnion *unionArrayPointer; 382 }; 383 384 // 385 // Intermediate class for node types that hold operators. 386 // 387 class TIntermOperator : public TIntermTyped { 388 public: 389 TOperator getOp() const { return op; } 390 void setOp(TOperator o) { op = o; } 391 392 bool modifiesState() const; 393 bool isConstructor() const; 394 395 protected: 396 TIntermOperator(TOperator o) : TIntermTyped(TType(EbtFloat, EbpUndefined)), op(o) {} 397 TIntermOperator(TOperator o, TType& t) : TIntermTyped(t), op(o) {} 398 TOperator op; 399 }; 400 401 // 402 // Nodes for all the basic binary math operators. 403 // 404 class TIntermBinary : public TIntermOperator { 405 public: 406 TIntermBinary(TOperator o) : TIntermOperator(o), addIndexClamp(false) {} 407 408 virtual TIntermBinary* getAsBinaryNode() { return this; } 409 virtual void traverse(TIntermTraverser*); 410 411 void setLeft(TIntermTyped* n) { left = n; } 412 void setRight(TIntermTyped* n) { right = n; } 413 TIntermTyped* getLeft() const { return left; } 414 TIntermTyped* getRight() const { return right; } 415 bool promote(TInfoSink&); 416 417 void setAddIndexClamp() { addIndexClamp = true; } 418 bool getAddIndexClamp() { return addIndexClamp; } 419 420 protected: 421 TIntermTyped* left; 422 TIntermTyped* right; 423 424 // If set to true, wrap any EOpIndexIndirect with a clamp to bounds. 425 bool addIndexClamp; 426 }; 427 428 // 429 // Nodes for unary math operators. 430 // 431 class TIntermUnary : public TIntermOperator { 432 public: 433 TIntermUnary(TOperator o, TType& t) : TIntermOperator(o, t), operand(0), useEmulatedFunction(false) {} 434 TIntermUnary(TOperator o) : TIntermOperator(o), operand(0), useEmulatedFunction(false) {} 435 436 virtual void traverse(TIntermTraverser*); 437 virtual TIntermUnary* getAsUnaryNode() { return this; } 438 439 void setOperand(TIntermTyped* o) { operand = o; } 440 TIntermTyped* getOperand() { return operand; } 441 bool promote(TInfoSink&); 442 443 void setUseEmulatedFunction() { useEmulatedFunction = true; } 444 bool getUseEmulatedFunction() { return useEmulatedFunction; } 445 446 protected: 447 TIntermTyped* operand; 448 449 // If set to true, replace the built-in function call with an emulated one 450 // to work around driver bugs. 451 bool useEmulatedFunction; 452 }; 453 454 typedef TVector<TIntermNode*> TIntermSequence; 455 typedef TVector<int> TQualifierList; 456 457 // 458 // Nodes that operate on an arbitrary sized set of children. 459 // 460 class TIntermAggregate : public TIntermOperator { 461 public: 462 TIntermAggregate() : TIntermOperator(EOpNull), userDefined(false), useEmulatedFunction(false) { } 463 TIntermAggregate(TOperator o) : TIntermOperator(o), useEmulatedFunction(false) { } 464 ~TIntermAggregate() { } 465 466 virtual TIntermAggregate* getAsAggregate() { return this; } 467 virtual void traverse(TIntermTraverser*); 468 469 TIntermSequence& getSequence() { return sequence; } 470 471 void setName(const TString& n) { name = n; } 472 const TString& getName() const { return name; } 473 474 void setUserDefined() { userDefined = true; } 475 bool isUserDefined() const { return userDefined; } 476 477 void setOptimize(bool o) { optimize = o; } 478 bool getOptimize() { return optimize; } 479 void setDebug(bool d) { debug = d; } 480 bool getDebug() { return debug; } 481 482 void setUseEmulatedFunction() { useEmulatedFunction = true; } 483 bool getUseEmulatedFunction() { return useEmulatedFunction; } 484 485 protected: 486 TIntermAggregate(const TIntermAggregate&); // disallow copy constructor 487 TIntermAggregate& operator=(const TIntermAggregate&); // disallow assignment operator 488 TIntermSequence sequence; 489 TString name; 490 bool userDefined; // used for user defined function names 491 492 bool optimize; 493 bool debug; 494 495 // If set to true, replace the built-in function call with an emulated one 496 // to work around driver bugs. 497 bool useEmulatedFunction; 498 }; 499 500 // 501 // For if tests. Simplified since there is no switch statement. 502 // 503 class TIntermSelection : public TIntermTyped { 504 public: 505 TIntermSelection(TIntermTyped* cond, TIntermNode* trueB, TIntermNode* falseB) : 506 TIntermTyped(TType(EbtVoid, EbpUndefined)), condition(cond), trueBlock(trueB), falseBlock(falseB) {} 507 TIntermSelection(TIntermTyped* cond, TIntermNode* trueB, TIntermNode* falseB, const TType& type) : 508 TIntermTyped(type), condition(cond), trueBlock(trueB), falseBlock(falseB) {} 509 510 virtual void traverse(TIntermTraverser*); 511 512 bool usesTernaryOperator() const { return getBasicType() != EbtVoid; } 513 TIntermNode* getCondition() const { return condition; } 514 TIntermNode* getTrueBlock() const { return trueBlock; } 515 TIntermNode* getFalseBlock() const { return falseBlock; } 516 TIntermSelection* getAsSelectionNode() { return this; } 517 518 protected: 519 TIntermTyped* condition; 520 TIntermNode* trueBlock; 521 TIntermNode* falseBlock; 522 }; 523 524 enum Visit 525 { 526 PreVisit, 527 InVisit, 528 PostVisit 529 }; 530 531 // 532 // For traversing the tree. User should derive from this, 533 // put their traversal specific data in it, and then pass 534 // it to a Traverse method. 535 // 536 // When using this, just fill in the methods for nodes you want visited. 537 // Return false from a pre-visit to skip visiting that node's subtree. 538 // 539 class TIntermTraverser 540 { 541 public: 542 POOL_ALLOCATOR_NEW_DELETE(); 543 TIntermTraverser(bool preVisit = true, bool inVisit = false, bool postVisit = false, bool rightToLeft = false) : 544 preVisit(preVisit), 545 inVisit(inVisit), 546 postVisit(postVisit), 547 rightToLeft(rightToLeft), 548 depth(0), 549 maxDepth(0) {} 550 virtual ~TIntermTraverser() {}; 551 552 virtual void visitSymbol(TIntermSymbol*) {} 553 virtual void visitConstantUnion(TIntermConstantUnion*) {} 554 virtual bool visitBinary(Visit visit, TIntermBinary*) {return true;} 555 virtual bool visitUnary(Visit visit, TIntermUnary*) {return true;} 556 virtual bool visitSelection(Visit visit, TIntermSelection*) {return true;} 557 virtual bool visitAggregate(Visit visit, TIntermAggregate*) {return true;} 558 virtual bool visitLoop(Visit visit, TIntermLoop*) {return true;} 559 virtual bool visitBranch(Visit visit, TIntermBranch*) {return true;} 560 561 int getMaxDepth() const {return maxDepth;} 562 void incrementDepth() {depth++; maxDepth = std::max(maxDepth, depth); } 563 void decrementDepth() {depth--;} 564 565 // Return the original name if hash function pointer is NULL; 566 // otherwise return the hashed name. 567 static TString hash(const TString& name, ShHashFunction64 hashFunction); 568 569 const bool preVisit; 570 const bool inVisit; 571 const bool postVisit; 572 const bool rightToLeft; 573 574 protected: 575 int depth; 576 int maxDepth; 577 }; 578 579 #endif // __INTERMEDIATE_H 580