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 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