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.
8 // Definition of the in-memory high-level intermediate representation
9 // of shaders. This is a tree that parser creates.
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.
16 #ifndef __INTERMEDIATE_H
17 #define __INTERMEDIATE_H
19 #include "GLSLANG/ShaderLang.h"
23 #include "compiler/translator/Common.h"
24 #include "compiler/translator/Types.h"
25 #include "compiler/translator/ConstantUnion.h"
28 // Operators used by the high-level (parse tree) representation.
31 EOpNull, // if in a node, should only mean a node is still being built
32 EOpSequence, // denotes a list of statements, or parameters, etc.
34 EOpFunction, // For function definition
35 EOpParameters, // an aggregate listing the parameters to a function
94 // Built-in functions potentially mapped to operators
136 EOpDFdx, // Fragment only, OES_standard_derivatives extension
137 EOpDFdy, // Fragment only, OES_standard_derivatives extension
138 EOpFwidth, // Fragment only, OES_standard_derivatives extension
140 EOpMatrixTimesMatrix,
149 EOpKill, // Fragment only
184 EOpVectorTimesMatrixAssign,
185 EOpVectorTimesScalarAssign,
186 EOpMatrixTimesScalarAssign,
187 EOpMatrixTimesMatrixAssign,
191 extern const char* getOperatorString(TOperator op);
193 class TIntermTraverser;
194 class TIntermAggregate;
197 class TIntermConstantUnion;
198 class TIntermSelection;
206 // Base class for the tree nodes
210 POOL_ALLOCATOR_NEW_DELETE();
212 // TODO: Move this to TSourceLoc constructor
213 // after getting rid of TPublicType.
214 line.first_file = line.last_file = 0;
215 line.first_line = line.last_line = 0;
217 virtual ~TIntermNode() { }
219 const TSourceLoc& getLine() const { return line; }
220 void setLine(const TSourceLoc& l) { line = l; }
222 virtual void traverse(TIntermTraverser*) = 0;
223 virtual TIntermTyped* getAsTyped() { return 0; }
224 virtual TIntermConstantUnion* getAsConstantUnion() { return 0; }
225 virtual TIntermAggregate* getAsAggregate() { return 0; }
226 virtual TIntermBinary* getAsBinaryNode() { return 0; }
227 virtual TIntermUnary* getAsUnaryNode() { return 0; }
228 virtual TIntermSelection* getAsSelectionNode() { return 0; }
229 virtual TIntermSymbol* getAsSymbolNode() { return 0; }
230 virtual TIntermLoop* getAsLoopNode() { return 0; }
231 virtual TIntermRaw* getAsRawNode() { return 0; }
233 // Replace a child node. Return true if |original| is a child
234 // node and it is replaced; otherwise, return false.
235 virtual bool replaceChildNode(
236 TIntermNode *original, TIntermNode *replacement) = 0;
238 // For traversing a tree in no particular order, but using
240 virtual void enqueueChildren(std::queue<TIntermNode*> *nodeQueue) const = 0;
247 // This is just to help yacc.
249 struct TIntermNodePair {
255 // Intermediate class for nodes that have a type.
257 class TIntermTyped : public TIntermNode {
259 TIntermTyped(const TType& t) : type(t) { }
260 virtual TIntermTyped* getAsTyped() { return this; }
262 virtual bool hasSideEffects() const = 0;
264 void setType(const TType& t) { type = t; }
265 const TType& getType() const { return type; }
266 TType* getTypePointer() { return &type; }
268 TBasicType getBasicType() const { return type.getBasicType(); }
269 TQualifier getQualifier() const { return type.getQualifier(); }
270 TPrecision getPrecision() const { return type.getPrecision(); }
271 int getNominalSize() const { return type.getNominalSize(); }
273 bool isMatrix() const { return type.isMatrix(); }
274 bool isArray() const { return type.isArray(); }
275 bool isVector() const { return type.isVector(); }
276 bool isScalar() const { return type.isScalar(); }
277 const char* getBasicString() const { return type.getBasicString(); }
278 const char* getQualifierString() const { return type.getQualifierString(); }
279 TString getCompleteString() const { return type.getCompleteString(); }
281 int totalRegisterCount() const { return type.totalRegisterCount(); }
282 int elementRegisterCount() const { return type.elementRegisterCount(); }
283 int getArraySize() const { return type.getArraySize(); }
290 // Handle for, do-while, and while loops.
298 class TIntermLoop : public TIntermNode {
300 TIntermLoop(TLoopType aType,
301 TIntermNode *aInit, TIntermTyped* aCond, TIntermTyped* aExpr,
302 TIntermNode* aBody) :
308 unrollFlag(false) { }
310 virtual TIntermLoop* getAsLoopNode() { return this; }
311 virtual void traverse(TIntermTraverser*);
312 virtual bool replaceChildNode(
313 TIntermNode *original, TIntermNode *replacement);
315 TLoopType getType() const { return type; }
316 TIntermNode* getInit() { return init; }
317 TIntermTyped* getCondition() { return cond; }
318 TIntermTyped* getExpression() { return expr; }
319 TIntermNode* getBody() { return body; }
321 void setUnrollFlag(bool flag) { unrollFlag = flag; }
322 bool getUnrollFlag() { return unrollFlag; }
324 virtual void enqueueChildren(std::queue<TIntermNode*> *nodeQueue) const;
328 TIntermNode* init; // for-loop initialization
329 TIntermTyped* cond; // loop exit condition
330 TIntermTyped* expr; // for-loop expression
331 TIntermNode* body; // loop body
333 bool unrollFlag; // Whether the loop should be unrolled or not.
337 // Handle break, continue, return, and kill.
339 class TIntermBranch : public TIntermNode {
341 TIntermBranch(TOperator op, TIntermTyped* e) :
345 virtual void traverse(TIntermTraverser*);
346 virtual bool replaceChildNode(
347 TIntermNode *original, TIntermNode *replacement);
349 TOperator getFlowOp() { return flowOp; }
350 TIntermTyped* getExpression() { return expression; }
352 virtual void enqueueChildren(std::queue<TIntermNode*> *nodeQueue) const;
356 TIntermTyped* expression; // non-zero except for "return exp;" statements
360 // Nodes that correspond to symbols or constants in the source code.
362 class TIntermSymbol : public TIntermTyped {
364 // if symbol is initialized as symbol(sym), the memory comes from the poolallocator of sym. If sym comes from
365 // per process globalpoolallocator, then it causes increased memory usage per compile
366 // it is essential to use "symbol = sym" to assign to symbol
367 TIntermSymbol(int i, const TString& sym, const TType& t) :
368 TIntermTyped(t), id(i) { symbol = sym; }
370 virtual bool hasSideEffects() const { return false; }
372 int getId() const { return id; }
373 const TString& getSymbol() const { return symbol; }
375 void setId(int newId) { id = newId; }
377 virtual void traverse(TIntermTraverser*);
378 virtual TIntermSymbol* getAsSymbolNode() { return this; }
379 virtual bool replaceChildNode(TIntermNode *, TIntermNode *) { return false; }
381 virtual void enqueueChildren(std::queue<TIntermNode*> *nodeQueue) const {}
388 // A Raw node stores raw code, that the translator will insert verbatim
389 // into the output stream. Useful for transformation operations that make
390 // complex code that might not fit naturally into the GLSL model.
391 class TIntermRaw : public TIntermTyped {
393 TIntermRaw(const TType &t, const TString &rawTextIn)
394 : TIntermTyped(t), rawText(rawTextIn)
397 virtual bool hasSideEffects() const { return false; }
399 TString getRawText() const { return rawText; }
401 virtual void traverse(TIntermTraverser*);
403 virtual TIntermRaw* getAsRawNode() { return this; }
404 virtual bool replaceChildNode(TIntermNode *, TIntermNode *) { return false; }
406 virtual void enqueueChildren(std::queue<TIntermNode*> *nodeQueue) const {}
412 class TIntermConstantUnion : public TIntermTyped {
414 TIntermConstantUnion(ConstantUnion *unionPointer, const TType& t) : TIntermTyped(t), unionArrayPointer(unionPointer) { }
416 virtual bool hasSideEffects() const { return false; }
418 ConstantUnion* getUnionArrayPointer() const { return unionArrayPointer; }
420 int getIConst(size_t index) const { return unionArrayPointer ? unionArrayPointer[index].getIConst() : 0; }
421 float getFConst(size_t index) const { return unionArrayPointer ? unionArrayPointer[index].getFConst() : 0.0f; }
422 bool getBConst(size_t index) const { return unionArrayPointer ? unionArrayPointer[index].getBConst() : false; }
424 virtual TIntermConstantUnion* getAsConstantUnion() { return this; }
425 virtual void traverse(TIntermTraverser*);
426 virtual bool replaceChildNode(TIntermNode *, TIntermNode *) { return false; }
428 TIntermTyped* fold(TOperator, TIntermTyped*, TInfoSink&);
430 virtual void enqueueChildren(std::queue<TIntermNode*> *nodeQueue) const {}
433 ConstantUnion *unionArrayPointer;
437 // Intermediate class for node types that hold operators.
439 class TIntermOperator : public TIntermTyped {
441 TOperator getOp() const { return op; }
442 void setOp(TOperator o) { op = o; }
444 bool isAssignment() const;
445 bool isConstructor() const;
447 virtual bool hasSideEffects() const { return isAssignment(); }
450 TIntermOperator(TOperator o) : TIntermTyped(TType(EbtFloat, EbpUndefined)), op(o) {}
451 TIntermOperator(TOperator o, const TType& t) : TIntermTyped(t), op(o) {}
456 // Nodes for all the basic binary math operators.
458 class TIntermBinary : public TIntermOperator {
460 TIntermBinary(TOperator o) : TIntermOperator(o), addIndexClamp(false) {}
462 virtual TIntermBinary* getAsBinaryNode() { return this; }
463 virtual void traverse(TIntermTraverser*);
464 virtual bool replaceChildNode(
465 TIntermNode *original, TIntermNode *replacement);
467 virtual bool hasSideEffects() const { return (isAssignment() || left->hasSideEffects() || right->hasSideEffects()); }
469 void setLeft(TIntermTyped* n) { left = n; }
470 void setRight(TIntermTyped* n) { right = n; }
471 TIntermTyped* getLeft() const { return left; }
472 TIntermTyped* getRight() const { return right; }
473 bool promote(TInfoSink&);
475 void setAddIndexClamp() { addIndexClamp = true; }
476 bool getAddIndexClamp() { return addIndexClamp; }
478 virtual void enqueueChildren(std::queue<TIntermNode*> *nodeQueue) const;
484 // If set to true, wrap any EOpIndexIndirect with a clamp to bounds.
489 // Nodes for unary math operators.
491 class TIntermUnary : public TIntermOperator {
493 TIntermUnary(TOperator o, const TType& t) : TIntermOperator(o, t), operand(0), useEmulatedFunction(false) {}
494 TIntermUnary(TOperator o) : TIntermOperator(o), operand(0), useEmulatedFunction(false) {}
496 virtual void traverse(TIntermTraverser*);
497 virtual TIntermUnary* getAsUnaryNode() { return this; }
498 virtual bool replaceChildNode(
499 TIntermNode *original, TIntermNode *replacement);
501 virtual bool hasSideEffects() const { return (isAssignment() || operand->hasSideEffects()); }
503 void setOperand(TIntermTyped* o) { operand = o; }
504 TIntermTyped* getOperand() { return operand; }
505 bool promote(TInfoSink&);
507 void setUseEmulatedFunction() { useEmulatedFunction = true; }
508 bool getUseEmulatedFunction() { return useEmulatedFunction; }
510 virtual void enqueueChildren(std::queue<TIntermNode*> *nodeQueue) const;
513 TIntermTyped* operand;
515 // If set to true, replace the built-in function call with an emulated one
516 // to work around driver bugs.
517 bool useEmulatedFunction;
520 typedef TVector<TIntermNode*> TIntermSequence;
521 typedef TVector<int> TQualifierList;
524 // Nodes that operate on an arbitrary sized set of children.
526 class TIntermAggregate : public TIntermOperator {
528 TIntermAggregate() : TIntermOperator(EOpNull), userDefined(false), useEmulatedFunction(false) { }
529 TIntermAggregate(TOperator o) : TIntermOperator(o), useEmulatedFunction(false) { }
530 ~TIntermAggregate() { }
532 virtual TIntermAggregate* getAsAggregate() { return this; }
533 virtual void traverse(TIntermTraverser*);
534 virtual bool replaceChildNode(
535 TIntermNode *original, TIntermNode *replacement);
537 // Conservatively assume function calls and other aggregate operators have side-effects
538 virtual bool hasSideEffects() const { return true; }
540 TIntermSequence& getSequence() { return sequence; }
542 void setName(const TString& n) { name = n; }
543 const TString& getName() const { return name; }
545 void setUserDefined() { userDefined = true; }
546 bool isUserDefined() const { return userDefined; }
548 void setOptimize(bool o) { optimize = o; }
549 bool getOptimize() { return optimize; }
550 void setDebug(bool d) { debug = d; }
551 bool getDebug() { return debug; }
553 void setUseEmulatedFunction() { useEmulatedFunction = true; }
554 bool getUseEmulatedFunction() { return useEmulatedFunction; }
556 virtual void enqueueChildren(std::queue<TIntermNode*> *nodeQueue) const;
559 TIntermAggregate(const TIntermAggregate&); // disallow copy constructor
560 TIntermAggregate& operator=(const TIntermAggregate&); // disallow assignment operator
561 TIntermSequence sequence;
563 bool userDefined; // used for user defined function names
568 // If set to true, replace the built-in function call with an emulated one
569 // to work around driver bugs.
570 bool useEmulatedFunction;
574 // For if tests. Simplified since there is no switch statement.
576 class TIntermSelection : public TIntermTyped {
578 TIntermSelection(TIntermTyped* cond, TIntermNode* trueB, TIntermNode* falseB) :
579 TIntermTyped(TType(EbtVoid, EbpUndefined)), condition(cond), trueBlock(trueB), falseBlock(falseB) {}
580 TIntermSelection(TIntermTyped* cond, TIntermNode* trueB, TIntermNode* falseB, const TType& type) :
581 TIntermTyped(type), condition(cond), trueBlock(trueB), falseBlock(falseB) {}
583 virtual void traverse(TIntermTraverser*);
584 virtual bool replaceChildNode(
585 TIntermNode *original, TIntermNode *replacement);
587 // Conservatively assume selections have side-effects
588 virtual bool hasSideEffects() const { return true; }
590 bool usesTernaryOperator() const { return getBasicType() != EbtVoid; }
591 TIntermNode* getCondition() const { return condition; }
592 TIntermNode* getTrueBlock() const { return trueBlock; }
593 TIntermNode* getFalseBlock() const { return falseBlock; }
594 TIntermSelection* getAsSelectionNode() { return this; }
596 virtual void enqueueChildren(std::queue<TIntermNode*> *nodeQueue) const;
599 TIntermTyped* condition;
600 TIntermNode* trueBlock;
601 TIntermNode* falseBlock;
612 // For traversing the tree. User should derive from this,
613 // put their traversal specific data in it, and then pass
614 // it to a Traverse method.
616 // When using this, just fill in the methods for nodes you want visited.
617 // Return false from a pre-visit to skip visiting that node's subtree.
619 class TIntermTraverser
622 POOL_ALLOCATOR_NEW_DELETE();
623 TIntermTraverser(bool preVisit = true, bool inVisit = false, bool postVisit = false, bool rightToLeft = false) :
626 postVisit(postVisit),
627 rightToLeft(rightToLeft),
630 virtual ~TIntermTraverser() {}
632 virtual void visitSymbol(TIntermSymbol*) {}
633 virtual void visitRaw(TIntermRaw*) {}
634 virtual void visitConstantUnion(TIntermConstantUnion*) {}
635 virtual bool visitBinary(Visit visit, TIntermBinary*) {return true;}
636 virtual bool visitUnary(Visit visit, TIntermUnary*) {return true;}
637 virtual bool visitSelection(Visit visit, TIntermSelection*) {return true;}
638 virtual bool visitAggregate(Visit visit, TIntermAggregate*) {return true;}
639 virtual bool visitLoop(Visit visit, TIntermLoop*) {return true;}
640 virtual bool visitBranch(Visit visit, TIntermBranch*) {return true;}
642 int getMaxDepth() const {return maxDepth;}
644 void incrementDepth(TIntermNode *current)
647 maxDepth = std::max(maxDepth, depth);
648 path.push_back(current);
651 void decrementDepth()
657 TIntermNode *getParentNode()
659 return path.size() == 0 ? NULL : path.back();
662 // Return the original name if hash function pointer is NULL;
663 // otherwise return the hashed name.
664 static TString hash(const TString& name, ShHashFunction64 hashFunction);
668 const bool postVisit;
669 const bool rightToLeft;
675 // All the nodes from root to the current node's parent during traversing.
676 TVector<TIntermNode *> path;
680 // For traversing the tree, and computing max depth.
681 // Takes a maximum depth limit to prevent stack overflow.
683 class TMaxDepthTraverser : public TIntermTraverser
686 POOL_ALLOCATOR_NEW_DELETE();
687 TMaxDepthTraverser(int depthLimit)
688 : TIntermTraverser(true, true, false, false),
689 depthLimit(depthLimit)
692 virtual bool visitBinary(Visit visit, TIntermBinary*) { return depthCheck(); }
693 virtual bool visitUnary(Visit visit, TIntermUnary*) { return depthCheck(); }
694 virtual bool visitSelection(Visit visit, TIntermSelection*) { return depthCheck(); }
695 virtual bool visitAggregate(Visit visit, TIntermAggregate*) { return depthCheck(); }
696 virtual bool visitLoop(Visit visit, TIntermLoop*) { return depthCheck(); }
697 virtual bool visitBranch(Visit visit, TIntermBranch*) { return depthCheck(); }
702 bool depthCheck() const { return maxDepth < depthLimit; }
705 #endif // __INTERMEDIATE_H