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//
29enum 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
190extern const char* getOperatorString(TOperator op);
191
192class TIntermTraverser;
193class TIntermAggregate;
194class TIntermBinary;
195class TIntermUnary;
196class TIntermConstantUnion;
197class TIntermSelection;
198class TIntermTyped;
199class TIntermSymbol;
200class TIntermLoop;
201class TInfoSink;
202
203//
204// Base class for the tree nodes
205//
206class TIntermNode {
207public:
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
230protected:
231    TSourceLoc line;
232};
233
234//
235// This is just to help yacc.
236//
237struct TIntermNodePair {
238    TIntermNode* node1;
239    TIntermNode* node2;
240};
241
242//
243// Intermediate class for nodes that have a type.
244//
245class TIntermTyped : public TIntermNode {
246public:
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
271protected:
272    TType type;
273};
274
275//
276// Handle for, do-while, and while loops.
277//
278enum TLoopType {
279    ELoopFor,
280    ELoopWhile,
281    ELoopDoWhile
282};
283
284class TIntermLoop : public TIntermNode {
285public:
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
308protected:
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//
321class TIntermBranch : public TIntermNode {
322public:
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
332protected:
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//
340class TIntermSymbol : public TIntermTyped {
341public:
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
359protected:
360    int id;
361    TString symbol;
362    TString originalSymbol;
363};
364
365class TIntermConstantUnion : public TIntermTyped {
366public:
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
380protected:
381    ConstantUnion *unionArrayPointer;
382};
383
384//
385// Intermediate class for node types that hold operators.
386//
387class TIntermOperator : public TIntermTyped {
388public:
389    TOperator getOp() const { return op; }
390    void setOp(TOperator o) { op = o; }
391
392    bool modifiesState() const;
393    bool isConstructor() const;
394
395protected:
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//
404class TIntermBinary : public TIntermOperator {
405public:
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
420protected:
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//
431class TIntermUnary : public TIntermOperator {
432public:
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
446protected:
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
454typedef TVector<TIntermNode*> TIntermSequence;
455typedef TVector<int> TQualifierList;
456
457//
458// Nodes that operate on an arbitrary sized set of children.
459//
460class TIntermAggregate : public TIntermOperator {
461public:
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
485protected:
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//
503class TIntermSelection : public TIntermTyped {
504public:
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
518protected:
519    TIntermTyped* condition;
520    TIntermNode* trueBlock;
521    TIntermNode* falseBlock;
522};
523
524enum 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//
539class TIntermTraverser
540{
541public:
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
574protected:
575    int depth;
576    int maxDepth;
577};
578
579#endif // __INTERMEDIATE_H
580