Home | History | Annotate | Download | only in compiler
      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     // Replace a child node. Return true if |original| is a child
    231     // node and it is replaced; otherwise, return false.
    232     virtual bool replaceChildNode(
    233         TIntermNode *original, TIntermNode *replacement) = 0;
    234 
    235 protected:
    236     TSourceLoc line;
    237 };
    238 
    239 //
    240 // This is just to help yacc.
    241 //
    242 struct TIntermNodePair {
    243     TIntermNode* node1;
    244     TIntermNode* node2;
    245 };
    246 
    247 //
    248 // Intermediate class for nodes that have a type.
    249 //
    250 class TIntermTyped : public TIntermNode {
    251 public:
    252     TIntermTyped(const TType& t) : type(t)  { }
    253     virtual TIntermTyped* getAsTyped() { return this; }
    254 
    255     virtual bool hasSideEffects() const = 0;
    256 
    257     void setType(const TType& t) { type = t; }
    258     const TType& getType() const { return type; }
    259     TType* getTypePointer() { return &type; }
    260 
    261     TBasicType getBasicType() const { return type.getBasicType(); }
    262     TQualifier getQualifier() const { return type.getQualifier(); }
    263     TPrecision getPrecision() const { return type.getPrecision(); }
    264     int getNominalSize() const { return type.getNominalSize(); }
    265 
    266     bool isMatrix() const { return type.isMatrix(); }
    267     bool isArray()  const { return type.isArray(); }
    268     bool isVector() const { return type.isVector(); }
    269     bool isScalar() const { return type.isScalar(); }
    270     const char* getBasicString() const { return type.getBasicString(); }
    271     const char* getQualifierString() const { return type.getQualifierString(); }
    272     TString getCompleteString() const { return type.getCompleteString(); }
    273 
    274     int totalRegisterCount() const { return type.totalRegisterCount(); }
    275     int elementRegisterCount() const { return type.elementRegisterCount(); }
    276     int getArraySize() const { return type.getArraySize(); }
    277 
    278 protected:
    279     TType type;
    280 };
    281 
    282 //
    283 // Handle for, do-while, and while loops.
    284 //
    285 enum TLoopType {
    286     ELoopFor,
    287     ELoopWhile,
    288     ELoopDoWhile
    289 };
    290 
    291 class TIntermLoop : public TIntermNode {
    292 public:
    293     TIntermLoop(TLoopType aType,
    294                 TIntermNode *aInit, TIntermTyped* aCond, TIntermTyped* aExpr,
    295                 TIntermNode* aBody) :
    296             type(aType),
    297             init(aInit),
    298             cond(aCond),
    299             expr(aExpr),
    300             body(aBody),
    301             unrollFlag(false) { }
    302 
    303     virtual TIntermLoop* getAsLoopNode() { return this; }
    304     virtual void traverse(TIntermTraverser*);
    305     virtual bool replaceChildNode(
    306         TIntermNode *original, TIntermNode *replacement);
    307 
    308     TLoopType getType() const { return type; }
    309     TIntermNode* getInit() { return init; }
    310     TIntermTyped* getCondition() { return cond; }
    311     TIntermTyped* getExpression() { return expr; }
    312     TIntermNode* getBody() { return body; }
    313 
    314     void setUnrollFlag(bool flag) { unrollFlag = flag; }
    315     bool getUnrollFlag() { return unrollFlag; }
    316 
    317 protected:
    318     TLoopType type;
    319     TIntermNode* init;  // for-loop initialization
    320     TIntermTyped* cond; // loop exit condition
    321     TIntermTyped* expr; // for-loop expression
    322     TIntermNode* body;  // loop body
    323 
    324     bool unrollFlag; // Whether the loop should be unrolled or not.
    325 };
    326 
    327 //
    328 // Handle break, continue, return, and kill.
    329 //
    330 class TIntermBranch : public TIntermNode {
    331 public:
    332     TIntermBranch(TOperator op, TIntermTyped* e) :
    333             flowOp(op),
    334             expression(e) { }
    335 
    336     virtual void traverse(TIntermTraverser*);
    337     virtual bool replaceChildNode(
    338         TIntermNode *original, TIntermNode *replacement);
    339 
    340     TOperator getFlowOp() { return flowOp; }
    341     TIntermTyped* getExpression() { return expression; }
    342 
    343 protected:
    344     TOperator flowOp;
    345     TIntermTyped* expression;  // non-zero except for "return exp;" statements
    346 };
    347 
    348 //
    349 // Nodes that correspond to symbols or constants in the source code.
    350 //
    351 class TIntermSymbol : public TIntermTyped {
    352 public:
    353     // if symbol is initialized as symbol(sym), the memory comes from the poolallocator of sym. If sym comes from
    354     // per process globalpoolallocator, then it causes increased memory usage per compile
    355     // it is essential to use "symbol = sym" to assign to symbol
    356     TIntermSymbol(int i, const TString& sym, const TType& t) :
    357             TIntermTyped(t), id(i)  { symbol = sym; originalSymbol = sym; }
    358 
    359     virtual bool hasSideEffects() const { return false; }
    360 
    361     int getId() const { return id; }
    362     const TString& getSymbol() const { return symbol; }
    363 
    364     void setId(int newId) { id = newId; }
    365     void setSymbol(const TString& sym) { symbol = sym; }
    366 
    367     const TString& getOriginalSymbol() const { return originalSymbol; }
    368 
    369     virtual void traverse(TIntermTraverser*);
    370     virtual TIntermSymbol* getAsSymbolNode() { return this; }
    371     virtual bool replaceChildNode(TIntermNode *, TIntermNode *) { return false; }
    372 
    373 protected:
    374     int id;
    375     TString symbol;
    376     TString originalSymbol;
    377 };
    378 
    379 class TIntermConstantUnion : public TIntermTyped {
    380 public:
    381     TIntermConstantUnion(ConstantUnion *unionPointer, const TType& t) : TIntermTyped(t), unionArrayPointer(unionPointer) { }
    382 
    383     virtual bool hasSideEffects() const { return false; }
    384 
    385     ConstantUnion* getUnionArrayPointer() const { return unionArrayPointer; }
    386 
    387     int getIConst(size_t index) const { return unionArrayPointer ? unionArrayPointer[index].getIConst() : 0; }
    388     float getFConst(size_t index) const { return unionArrayPointer ? unionArrayPointer[index].getFConst() : 0.0f; }
    389     bool getBConst(size_t index) const { return unionArrayPointer ? unionArrayPointer[index].getBConst() : false; }
    390 
    391     virtual TIntermConstantUnion* getAsConstantUnion()  { return this; }
    392     virtual void traverse(TIntermTraverser*);
    393     virtual bool replaceChildNode(TIntermNode *, TIntermNode *) { return false; }
    394 
    395     TIntermTyped* fold(TOperator, TIntermTyped*, TInfoSink&);
    396 
    397 protected:
    398     ConstantUnion *unionArrayPointer;
    399 };
    400 
    401 //
    402 // Intermediate class for node types that hold operators.
    403 //
    404 class TIntermOperator : public TIntermTyped {
    405 public:
    406     TOperator getOp() const { return op; }
    407     void setOp(TOperator o) { op = o; }
    408 
    409     bool isAssignment() const;
    410     bool isConstructor() const;
    411 
    412     virtual bool hasSideEffects() const { return isAssignment(); }
    413 
    414 protected:
    415     TIntermOperator(TOperator o) : TIntermTyped(TType(EbtFloat, EbpUndefined)), op(o) {}
    416     TIntermOperator(TOperator o, TType& t) : TIntermTyped(t), op(o) {}
    417     TOperator op;
    418 };
    419 
    420 //
    421 // Nodes for all the basic binary math operators.
    422 //
    423 class TIntermBinary : public TIntermOperator {
    424 public:
    425     TIntermBinary(TOperator o) : TIntermOperator(o), addIndexClamp(false) {}
    426 
    427     virtual TIntermBinary* getAsBinaryNode() { return this; }
    428     virtual void traverse(TIntermTraverser*);
    429     virtual bool replaceChildNode(
    430         TIntermNode *original, TIntermNode *replacement);
    431 
    432     virtual bool hasSideEffects() const { return (isAssignment() || left->hasSideEffects() || right->hasSideEffects()); }
    433 
    434     void setLeft(TIntermTyped* n) { left = n; }
    435     void setRight(TIntermTyped* n) { right = n; }
    436     TIntermTyped* getLeft() const { return left; }
    437     TIntermTyped* getRight() const { return right; }
    438     bool promote(TInfoSink&);
    439 
    440     void setAddIndexClamp() { addIndexClamp = true; }
    441     bool getAddIndexClamp() { return addIndexClamp; }
    442 
    443 protected:
    444     TIntermTyped* left;
    445     TIntermTyped* right;
    446 
    447     // If set to true, wrap any EOpIndexIndirect with a clamp to bounds.
    448     bool addIndexClamp;
    449 };
    450 
    451 //
    452 // Nodes for unary math operators.
    453 //
    454 class TIntermUnary : public TIntermOperator {
    455 public:
    456     TIntermUnary(TOperator o, TType& t) : TIntermOperator(o, t), operand(0), useEmulatedFunction(false) {}
    457     TIntermUnary(TOperator o) : TIntermOperator(o), operand(0), useEmulatedFunction(false) {}
    458 
    459     virtual void traverse(TIntermTraverser*);
    460     virtual TIntermUnary* getAsUnaryNode() { return this; }
    461     virtual bool replaceChildNode(
    462         TIntermNode *original, TIntermNode *replacement);
    463 
    464     virtual bool hasSideEffects() const { return (isAssignment() || operand->hasSideEffects()); }
    465 
    466     void setOperand(TIntermTyped* o) { operand = o; }
    467     TIntermTyped* getOperand() { return operand; }
    468     bool promote(TInfoSink&);
    469 
    470     void setUseEmulatedFunction() { useEmulatedFunction = true; }
    471     bool getUseEmulatedFunction() { return useEmulatedFunction; }
    472 
    473 protected:
    474     TIntermTyped* operand;
    475 
    476     // If set to true, replace the built-in function call with an emulated one
    477     // to work around driver bugs.
    478     bool useEmulatedFunction;
    479 };
    480 
    481 typedef TVector<TIntermNode*> TIntermSequence;
    482 typedef TVector<int> TQualifierList;
    483 
    484 //
    485 // Nodes that operate on an arbitrary sized set of children.
    486 //
    487 class TIntermAggregate : public TIntermOperator {
    488 public:
    489     TIntermAggregate() : TIntermOperator(EOpNull), userDefined(false), useEmulatedFunction(false) { }
    490     TIntermAggregate(TOperator o) : TIntermOperator(o), useEmulatedFunction(false) { }
    491     ~TIntermAggregate() { }
    492 
    493     virtual TIntermAggregate* getAsAggregate() { return this; }
    494     virtual void traverse(TIntermTraverser*);
    495     virtual bool replaceChildNode(
    496         TIntermNode *original, TIntermNode *replacement);
    497 
    498     // Conservatively assume function calls and other aggregate operators have side-effects
    499     virtual bool hasSideEffects() const { return true; }
    500 
    501     TIntermSequence& getSequence() { return sequence; }
    502 
    503     void setName(const TString& n) { name = n; }
    504     const TString& getName() const { return name; }
    505 
    506     void setUserDefined() { userDefined = true; }
    507     bool isUserDefined() const { return userDefined; }
    508 
    509     void setOptimize(bool o) { optimize = o; }
    510     bool getOptimize() { return optimize; }
    511     void setDebug(bool d) { debug = d; }
    512     bool getDebug() { return debug; }
    513 
    514     void setUseEmulatedFunction() { useEmulatedFunction = true; }
    515     bool getUseEmulatedFunction() { return useEmulatedFunction; }
    516 
    517 protected:
    518     TIntermAggregate(const TIntermAggregate&); // disallow copy constructor
    519     TIntermAggregate& operator=(const TIntermAggregate&); // disallow assignment operator
    520     TIntermSequence sequence;
    521     TString name;
    522     bool userDefined; // used for user defined function names
    523 
    524     bool optimize;
    525     bool debug;
    526 
    527     // If set to true, replace the built-in function call with an emulated one
    528     // to work around driver bugs.
    529     bool useEmulatedFunction;
    530 };
    531 
    532 //
    533 // For if tests.  Simplified since there is no switch statement.
    534 //
    535 class TIntermSelection : public TIntermTyped {
    536 public:
    537     TIntermSelection(TIntermTyped* cond, TIntermNode* trueB, TIntermNode* falseB) :
    538             TIntermTyped(TType(EbtVoid, EbpUndefined)), condition(cond), trueBlock(trueB), falseBlock(falseB) {}
    539     TIntermSelection(TIntermTyped* cond, TIntermNode* trueB, TIntermNode* falseB, const TType& type) :
    540             TIntermTyped(type), condition(cond), trueBlock(trueB), falseBlock(falseB) {}
    541 
    542     virtual void traverse(TIntermTraverser*);
    543     virtual bool replaceChildNode(
    544         TIntermNode *original, TIntermNode *replacement);
    545 
    546     // Conservatively assume selections have side-effects
    547     virtual bool hasSideEffects() const { return true; }
    548 
    549     bool usesTernaryOperator() const { return getBasicType() != EbtVoid; }
    550     TIntermNode* getCondition() const { return condition; }
    551     TIntermNode* getTrueBlock() const { return trueBlock; }
    552     TIntermNode* getFalseBlock() const { return falseBlock; }
    553     TIntermSelection* getAsSelectionNode() { return this; }
    554 
    555 protected:
    556     TIntermTyped* condition;
    557     TIntermNode* trueBlock;
    558     TIntermNode* falseBlock;
    559 };
    560 
    561 enum Visit
    562 {
    563     PreVisit,
    564     InVisit,
    565     PostVisit
    566 };
    567 
    568 //
    569 // For traversing the tree.  User should derive from this,
    570 // put their traversal specific data in it, and then pass
    571 // it to a Traverse method.
    572 //
    573 // When using this, just fill in the methods for nodes you want visited.
    574 // Return false from a pre-visit to skip visiting that node's subtree.
    575 //
    576 class TIntermTraverser
    577 {
    578 public:
    579     POOL_ALLOCATOR_NEW_DELETE();
    580     TIntermTraverser(bool preVisit = true, bool inVisit = false, bool postVisit = false, bool rightToLeft = false) :
    581             preVisit(preVisit),
    582             inVisit(inVisit),
    583             postVisit(postVisit),
    584             rightToLeft(rightToLeft),
    585             depth(0),
    586             maxDepth(0) {}
    587     virtual ~TIntermTraverser() {}
    588 
    589     virtual void visitSymbol(TIntermSymbol*) {}
    590     virtual void visitConstantUnion(TIntermConstantUnion*) {}
    591     virtual bool visitBinary(Visit visit, TIntermBinary*) {return true;}
    592     virtual bool visitUnary(Visit visit, TIntermUnary*) {return true;}
    593     virtual bool visitSelection(Visit visit, TIntermSelection*) {return true;}
    594     virtual bool visitAggregate(Visit visit, TIntermAggregate*) {return true;}
    595     virtual bool visitLoop(Visit visit, TIntermLoop*) {return true;}
    596     virtual bool visitBranch(Visit visit, TIntermBranch*) {return true;}
    597 
    598     int getMaxDepth() const {return maxDepth;}
    599 
    600     void incrementDepth(TIntermNode *current)
    601     {
    602         depth++;
    603         maxDepth = std::max(maxDepth, depth);
    604         path.push_back(current);
    605     }
    606 
    607     void decrementDepth()
    608     {
    609         depth--;
    610         path.pop_back();
    611     }
    612 
    613     TIntermNode *getParentNode()
    614     {
    615         return path.size() == 0 ? NULL : path.back();
    616     }
    617 
    618     // Return the original name if hash function pointer is NULL;
    619     // otherwise return the hashed name.
    620     static TString hash(const TString& name, ShHashFunction64 hashFunction);
    621 
    622     const bool preVisit;
    623     const bool inVisit;
    624     const bool postVisit;
    625     const bool rightToLeft;
    626 
    627 protected:
    628     int depth;
    629     int maxDepth;
    630 
    631     // All the nodes from root to the current node's parent during traversing.
    632     TVector<TIntermNode *> path;
    633 };
    634 
    635 #endif // __INTERMEDIATE_H
    636