blob: 2d52900ab0686eef019bc32cdda0655ec625ae47 [file] [log] [blame]
Jamie Madillb1a85f42014-08-19 15:23:24 -04001//
2// Copyright (c) 2002-2014 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
Geoff Lang0a73dd82014-11-19 16:18:08 -050016#ifndef COMPILER_TRANSLATOR_INTERMNODE_H_
17#define COMPILER_TRANSLATOR_INTERMNODE_H_
Jamie Madillb1a85f42014-08-19 15:23:24 -040018
19#include "GLSLANG/ShaderLang.h"
20
21#include <algorithm>
22#include <queue>
23
24#include "compiler/translator/Common.h"
25#include "compiler/translator/Types.h"
26#include "compiler/translator/ConstantUnion.h"
Olli Etuaho1033e1d2015-02-12 12:03:13 +020027#include "compiler/translator/Operator.h"
Jamie Madillb1a85f42014-08-19 15:23:24 -040028
29class TIntermTraverser;
30class TIntermAggregate;
31class TIntermBinary;
32class TIntermUnary;
33class TIntermConstantUnion;
34class TIntermSelection;
35class TIntermTyped;
36class TIntermSymbol;
37class TIntermLoop;
38class TInfoSink;
Olli Etuahoa3a5cc62015-02-13 13:12:22 +020039class TInfoSinkBase;
Jamie Madillb1a85f42014-08-19 15:23:24 -040040class TIntermRaw;
41
42//
43// Base class for the tree nodes
44//
45class TIntermNode
46{
47 public:
48 POOL_ALLOCATOR_NEW_DELETE();
49 TIntermNode()
50 {
51 // TODO: Move this to TSourceLoc constructor
52 // after getting rid of TPublicType.
53 mLine.first_file = mLine.last_file = 0;
54 mLine.first_line = mLine.last_line = 0;
55 }
56 virtual ~TIntermNode() { }
57
58 const TSourceLoc &getLine() const { return mLine; }
59 void setLine(const TSourceLoc &l) { mLine = l; }
60
61 virtual void traverse(TIntermTraverser *) = 0;
62 virtual TIntermTyped *getAsTyped() { return 0; }
63 virtual TIntermConstantUnion *getAsConstantUnion() { return 0; }
64 virtual TIntermAggregate *getAsAggregate() { return 0; }
65 virtual TIntermBinary *getAsBinaryNode() { return 0; }
66 virtual TIntermUnary *getAsUnaryNode() { return 0; }
67 virtual TIntermSelection *getAsSelectionNode() { return 0; }
68 virtual TIntermSymbol *getAsSymbolNode() { return 0; }
69 virtual TIntermLoop *getAsLoopNode() { return 0; }
70 virtual TIntermRaw *getAsRawNode() { return 0; }
71
72 // Replace a child node. Return true if |original| is a child
73 // node and it is replaced; otherwise, return false.
74 virtual bool replaceChildNode(
75 TIntermNode *original, TIntermNode *replacement) = 0;
76
Jamie Madillb1a85f42014-08-19 15:23:24 -040077 protected:
78 TSourceLoc mLine;
79};
80
81//
82// This is just to help yacc.
83//
84struct TIntermNodePair
85{
86 TIntermNode *node1;
87 TIntermNode *node2;
88};
89
90//
91// Intermediate class for nodes that have a type.
92//
93class TIntermTyped : public TIntermNode
94{
95 public:
96 TIntermTyped(const TType &t) : mType(t) { }
97 virtual TIntermTyped *getAsTyped() { return this; }
98
99 virtual bool hasSideEffects() const = 0;
100
101 void setType(const TType &t) { mType = t; }
Olli Etuahod2a67b92014-10-21 16:42:57 +0300102 void setTypePreservePrecision(const TType &t);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400103 const TType &getType() const { return mType; }
104 TType *getTypePointer() { return &mType; }
105
106 TBasicType getBasicType() const { return mType.getBasicType(); }
107 TQualifier getQualifier() const { return mType.getQualifier(); }
108 TPrecision getPrecision() const { return mType.getPrecision(); }
109 int getCols() const { return mType.getCols(); }
110 int getRows() const { return mType.getRows(); }
111 int getNominalSize() const { return mType.getNominalSize(); }
112 int getSecondarySize() const { return mType.getSecondarySize(); }
113
114 bool isInterfaceBlock() const { return mType.isInterfaceBlock(); }
115 bool isMatrix() const { return mType.isMatrix(); }
116 bool isArray() const { return mType.isArray(); }
117 bool isVector() const { return mType.isVector(); }
118 bool isScalar() const { return mType.isScalar(); }
119 bool isScalarInt() const { return mType.isScalarInt(); }
120 const char *getBasicString() const { return mType.getBasicString(); }
121 const char *getQualifierString() const { return mType.getQualifierString(); }
122 TString getCompleteString() const { return mType.getCompleteString(); }
123
124 int getArraySize() const { return mType.getArraySize(); }
125
126 protected:
127 TType mType;
128};
129
130//
131// Handle for, do-while, and while loops.
132//
133enum TLoopType
134{
135 ELoopFor,
136 ELoopWhile,
137 ELoopDoWhile
138};
139
140class TIntermLoop : public TIntermNode
141{
142 public:
143 TIntermLoop(TLoopType type,
144 TIntermNode *init, TIntermTyped *cond, TIntermTyped *expr,
145 TIntermNode *body)
146 : mType(type),
147 mInit(init),
148 mCond(cond),
149 mExpr(expr),
150 mBody(body),
151 mUnrollFlag(false) { }
152
153 virtual TIntermLoop *getAsLoopNode() { return this; }
154 virtual void traverse(TIntermTraverser *);
155 virtual bool replaceChildNode(
156 TIntermNode *original, TIntermNode *replacement);
157
158 TLoopType getType() const { return mType; }
159 TIntermNode *getInit() { return mInit; }
160 TIntermTyped *getCondition() { return mCond; }
161 TIntermTyped *getExpression() { return mExpr; }
162 TIntermNode *getBody() { return mBody; }
163
164 void setUnrollFlag(bool flag) { mUnrollFlag = flag; }
165 bool getUnrollFlag() const { return mUnrollFlag; }
166
Jamie Madillb1a85f42014-08-19 15:23:24 -0400167 protected:
168 TLoopType mType;
169 TIntermNode *mInit; // for-loop initialization
170 TIntermTyped *mCond; // loop exit condition
171 TIntermTyped *mExpr; // for-loop expression
172 TIntermNode *mBody; // loop body
173
174 bool mUnrollFlag; // Whether the loop should be unrolled or not.
175};
176
177//
178// Handle break, continue, return, and kill.
179//
180class TIntermBranch : public TIntermNode
181{
182 public:
183 TIntermBranch(TOperator op, TIntermTyped *e)
184 : mFlowOp(op),
185 mExpression(e) { }
186
187 virtual void traverse(TIntermTraverser *);
188 virtual bool replaceChildNode(
189 TIntermNode *original, TIntermNode *replacement);
190
191 TOperator getFlowOp() { return mFlowOp; }
192 TIntermTyped* getExpression() { return mExpression; }
193
Jamie Madillb1a85f42014-08-19 15:23:24 -0400194protected:
195 TOperator mFlowOp;
196 TIntermTyped *mExpression; // non-zero except for "return exp;" statements
197};
198
199//
200// Nodes that correspond to symbols or constants in the source code.
201//
202class TIntermSymbol : public TIntermTyped
203{
204 public:
205 // if symbol is initialized as symbol(sym), the memory comes from the poolallocator of sym.
206 // If sym comes from per process globalpoolallocator, then it causes increased memory usage
207 // per compile it is essential to use "symbol = sym" to assign to symbol
208 TIntermSymbol(int id, const TString &symbol, const TType &type)
209 : TIntermTyped(type),
210 mId(id)
211 {
212 mSymbol = symbol;
213 }
214
215 virtual bool hasSideEffects() const { return false; }
216
217 int getId() const { return mId; }
218 const TString &getSymbol() const { return mSymbol; }
219
220 void setId(int newId) { mId = newId; }
221
222 virtual void traverse(TIntermTraverser *);
223 virtual TIntermSymbol *getAsSymbolNode() { return this; }
224 virtual bool replaceChildNode(TIntermNode *, TIntermNode *) { return false; }
225
Jamie Madillb1a85f42014-08-19 15:23:24 -0400226 protected:
227 int mId;
228 TString mSymbol;
229};
230
231// A Raw node stores raw code, that the translator will insert verbatim
232// into the output stream. Useful for transformation operations that make
233// complex code that might not fit naturally into the GLSL model.
234class TIntermRaw : public TIntermTyped
235{
236 public:
237 TIntermRaw(const TType &type, const TString &rawText)
238 : TIntermTyped(type),
239 mRawText(rawText) { }
240
241 virtual bool hasSideEffects() const { return false; }
242
243 TString getRawText() const { return mRawText; }
244
245 virtual void traverse(TIntermTraverser *);
246
247 virtual TIntermRaw *getAsRawNode() { return this; }
248 virtual bool replaceChildNode(TIntermNode *, TIntermNode *) { return false; }
Jamie Madillb1a85f42014-08-19 15:23:24 -0400249
250 protected:
251 TString mRawText;
252};
253
254class TIntermConstantUnion : public TIntermTyped
255{
256 public:
257 TIntermConstantUnion(ConstantUnion *unionPointer, const TType &type)
258 : TIntermTyped(type),
259 mUnionArrayPointer(unionPointer) { }
260
261 virtual bool hasSideEffects() const { return false; }
262
263 ConstantUnion *getUnionArrayPointer() const { return mUnionArrayPointer; }
264
265 int getIConst(size_t index) const
266 {
267 return mUnionArrayPointer ? mUnionArrayPointer[index].getIConst() : 0;
268 }
269 unsigned int getUConst(size_t index) const
270 {
271 return mUnionArrayPointer ? mUnionArrayPointer[index].getUConst() : 0;
272 }
273 float getFConst(size_t index) const
274 {
275 return mUnionArrayPointer ? mUnionArrayPointer[index].getFConst() : 0.0f;
276 }
277 bool getBConst(size_t index) const
278 {
279 return mUnionArrayPointer ? mUnionArrayPointer[index].getBConst() : false;
280 }
281
282 virtual TIntermConstantUnion *getAsConstantUnion() { return this; }
283 virtual void traverse(TIntermTraverser *);
284 virtual bool replaceChildNode(TIntermNode *, TIntermNode *) { return false; }
285
286 TIntermTyped *fold(TOperator, TIntermTyped *, TInfoSink &);
287
Jamie Madillb1a85f42014-08-19 15:23:24 -0400288 protected:
289 ConstantUnion *mUnionArrayPointer;
290};
291
292//
293// Intermediate class for node types that hold operators.
294//
295class TIntermOperator : public TIntermTyped
296{
297 public:
298 TOperator getOp() const { return mOp; }
299 void setOp(TOperator op) { mOp = op; }
300
301 bool isAssignment() const;
302 bool isConstructor() const;
303
304 virtual bool hasSideEffects() const { return isAssignment(); }
305
306 protected:
307 TIntermOperator(TOperator op)
308 : TIntermTyped(TType(EbtFloat, EbpUndefined)),
309 mOp(op) {}
310 TIntermOperator(TOperator op, const TType &type)
311 : TIntermTyped(type),
312 mOp(op) {}
313
314 TOperator mOp;
315};
316
317//
318// Nodes for all the basic binary math operators.
319//
320class TIntermBinary : public TIntermOperator
321{
322 public:
323 TIntermBinary(TOperator op)
324 : TIntermOperator(op),
325 mAddIndexClamp(false) {}
326
327 virtual TIntermBinary *getAsBinaryNode() { return this; }
328 virtual void traverse(TIntermTraverser *);
329 virtual bool replaceChildNode(
330 TIntermNode *original, TIntermNode *replacement);
331
332 virtual bool hasSideEffects() const
333 {
334 return isAssignment() || mLeft->hasSideEffects() || mRight->hasSideEffects();
335 }
336
337 void setLeft(TIntermTyped *node) { mLeft = node; }
338 void setRight(TIntermTyped *node) { mRight = node; }
339 TIntermTyped *getLeft() const { return mLeft; }
340 TIntermTyped *getRight() const { return mRight; }
341 bool promote(TInfoSink &);
342
343 void setAddIndexClamp() { mAddIndexClamp = true; }
344 bool getAddIndexClamp() { return mAddIndexClamp; }
345
Jamie Madillb1a85f42014-08-19 15:23:24 -0400346 protected:
347 TIntermTyped* mLeft;
348 TIntermTyped* mRight;
349
350 // If set to true, wrap any EOpIndexIndirect with a clamp to bounds.
351 bool mAddIndexClamp;
352};
353
354//
355// Nodes for unary math operators.
356//
357class TIntermUnary : public TIntermOperator
358{
359 public:
360 TIntermUnary(TOperator op, const TType &type)
361 : TIntermOperator(op, type),
362 mOperand(NULL),
363 mUseEmulatedFunction(false) {}
364 TIntermUnary(TOperator op)
365 : TIntermOperator(op),
366 mOperand(NULL),
367 mUseEmulatedFunction(false) {}
368
369 virtual void traverse(TIntermTraverser *);
370 virtual TIntermUnary *getAsUnaryNode() { return this; }
371 virtual bool replaceChildNode(
372 TIntermNode *original, TIntermNode *replacement);
373
374 virtual bool hasSideEffects() const
375 {
376 return isAssignment() || mOperand->hasSideEffects();
377 }
378
379 void setOperand(TIntermTyped *operand) { mOperand = operand; }
380 TIntermTyped *getOperand() { return mOperand; }
381 bool promote(TInfoSink &);
382
383 void setUseEmulatedFunction() { mUseEmulatedFunction = true; }
384 bool getUseEmulatedFunction() { return mUseEmulatedFunction; }
385
Jamie Madillb1a85f42014-08-19 15:23:24 -0400386 protected:
387 TIntermTyped *mOperand;
388
389 // If set to true, replace the built-in function call with an emulated one
390 // to work around driver bugs.
391 bool mUseEmulatedFunction;
392};
393
394typedef TVector<TIntermNode *> TIntermSequence;
395typedef TVector<int> TQualifierList;
396
397//
398// Nodes that operate on an arbitrary sized set of children.
399//
400class TIntermAggregate : public TIntermOperator
401{
402 public:
403 TIntermAggregate()
404 : TIntermOperator(EOpNull),
405 mUserDefined(false),
406 mUseEmulatedFunction(false) { }
407 TIntermAggregate(TOperator op)
408 : TIntermOperator(op),
409 mUseEmulatedFunction(false) { }
410 ~TIntermAggregate() { }
411
412 virtual TIntermAggregate *getAsAggregate() { return this; }
413 virtual void traverse(TIntermTraverser *);
414 virtual bool replaceChildNode(
415 TIntermNode *original, TIntermNode *replacement);
416
417 // Conservatively assume function calls and other aggregate operators have side-effects
418 virtual bool hasSideEffects() const { return true; }
419
420 TIntermSequence *getSequence() { return &mSequence; }
421
422 void setName(const TString &name) { mName = name; }
423 const TString &getName() const { return mName; }
424
425 void setUserDefined() { mUserDefined = true; }
426 bool isUserDefined() const { return mUserDefined; }
427
428 void setOptimize(bool optimize) { mOptimize = optimize; }
429 bool getOptimize() const { return mOptimize; }
430 void setDebug(bool debug) { mDebug = debug; }
431 bool getDebug() const { return mDebug; }
432
433 void setUseEmulatedFunction() { mUseEmulatedFunction = true; }
434 bool getUseEmulatedFunction() { return mUseEmulatedFunction; }
435
Olli Etuahod2a67b92014-10-21 16:42:57 +0300436 void setPrecisionFromChildren();
437 void setBuiltInFunctionPrecision();
438
Jamie Madillb1a85f42014-08-19 15:23:24 -0400439 protected:
440 TIntermAggregate(const TIntermAggregate &); // disallow copy constructor
441 TIntermAggregate &operator=(const TIntermAggregate &); // disallow assignment operator
442 TIntermSequence mSequence;
443 TString mName;
444 bool mUserDefined; // used for user defined function names
445
446 bool mOptimize;
447 bool mDebug;
448
449 // If set to true, replace the built-in function call with an emulated one
450 // to work around driver bugs.
451 bool mUseEmulatedFunction;
452};
453
454//
455// For if tests. Simplified since there is no switch statement.
456//
457class TIntermSelection : public TIntermTyped
458{
459 public:
460 TIntermSelection(TIntermTyped *cond, TIntermNode *trueB, TIntermNode *falseB)
461 : TIntermTyped(TType(EbtVoid, EbpUndefined)),
462 mCondition(cond),
463 mTrueBlock(trueB),
464 mFalseBlock(falseB) {}
465 TIntermSelection(TIntermTyped *cond, TIntermNode *trueB, TIntermNode *falseB,
466 const TType &type)
467 : TIntermTyped(type),
468 mCondition(cond),
469 mTrueBlock(trueB),
470 mFalseBlock(falseB) {}
471
472 virtual void traverse(TIntermTraverser *);
473 virtual bool replaceChildNode(
474 TIntermNode *original, TIntermNode *replacement);
475
476 // Conservatively assume selections have side-effects
477 virtual bool hasSideEffects() const { return true; }
478
479 bool usesTernaryOperator() const { return getBasicType() != EbtVoid; }
480 TIntermNode *getCondition() const { return mCondition; }
481 TIntermNode *getTrueBlock() const { return mTrueBlock; }
482 TIntermNode *getFalseBlock() const { return mFalseBlock; }
483 TIntermSelection *getAsSelectionNode() { return this; }
484
Jamie Madillb1a85f42014-08-19 15:23:24 -0400485protected:
486 TIntermTyped *mCondition;
487 TIntermNode *mTrueBlock;
488 TIntermNode *mFalseBlock;
489};
490
491enum Visit
492{
493 PreVisit,
494 InVisit,
495 PostVisit
496};
497
498//
499// For traversing the tree. User should derive from this,
500// put their traversal specific data in it, and then pass
501// it to a Traverse method.
502//
503// When using this, just fill in the methods for nodes you want visited.
504// Return false from a pre-visit to skip visiting that node's subtree.
505//
506class TIntermTraverser
507{
508 public:
509 POOL_ALLOCATOR_NEW_DELETE();
510 // TODO(zmo): remove default values.
511 TIntermTraverser(bool preVisit = true, bool inVisit = false, bool postVisit = false,
512 bool rightToLeft = false)
513 : preVisit(preVisit),
514 inVisit(inVisit),
515 postVisit(postVisit),
516 rightToLeft(rightToLeft),
517 mDepth(0),
518 mMaxDepth(0) {}
519 virtual ~TIntermTraverser() {}
520
521 virtual void visitSymbol(TIntermSymbol *) {}
522 virtual void visitRaw(TIntermRaw *) {}
523 virtual void visitConstantUnion(TIntermConstantUnion *) {}
524 virtual bool visitBinary(Visit, TIntermBinary *) { return true; }
525 virtual bool visitUnary(Visit, TIntermUnary *) { return true; }
526 virtual bool visitSelection(Visit, TIntermSelection *) { return true; }
527 virtual bool visitAggregate(Visit, TIntermAggregate *) { return true; }
528 virtual bool visitLoop(Visit, TIntermLoop *) { return true; }
529 virtual bool visitBranch(Visit, TIntermBranch *) { return true; }
530
531 int getMaxDepth() const { return mMaxDepth; }
532
533 void incrementDepth(TIntermNode *current)
534 {
535 mDepth++;
536 mMaxDepth = std::max(mMaxDepth, mDepth);
537 mPath.push_back(current);
538 }
539
540 void decrementDepth()
541 {
542 mDepth--;
543 mPath.pop_back();
544 }
545
546 TIntermNode *getParentNode()
547 {
548 return mPath.size() == 0 ? NULL : mPath.back();
549 }
550
551 // Return the original name if hash function pointer is NULL;
552 // otherwise return the hashed name.
553 static TString hash(const TString& name, ShHashFunction64 hashFunction);
554
555 const bool preVisit;
556 const bool inVisit;
557 const bool postVisit;
558 const bool rightToLeft;
559
Olli Etuaho853dc1a2014-11-06 17:25:48 +0200560 // If traversers need to replace nodes, they can add the replacements in
561 // mReplacements during traversal and the user of the traverser should call
562 // this function after traversal to perform them.
563 void updateTree();
564
Jamie Madillb1a85f42014-08-19 15:23:24 -0400565 protected:
566 int mDepth;
567 int mMaxDepth;
568
569 // All the nodes from root to the current node's parent during traversing.
570 TVector<TIntermNode *> mPath;
Olli Etuaho853dc1a2014-11-06 17:25:48 +0200571
572 struct NodeUpdateEntry
573 {
574 NodeUpdateEntry(TIntermNode *_parent,
575 TIntermNode *_original,
576 TIntermNode *_replacement,
577 bool _originalBecomesChildOfReplacement)
578 : parent(_parent),
579 original(_original),
580 replacement(_replacement),
581 originalBecomesChildOfReplacement(_originalBecomesChildOfReplacement) {}
582
583 TIntermNode *parent;
584 TIntermNode *original;
585 TIntermNode *replacement;
586 bool originalBecomesChildOfReplacement;
587 };
588
589 // During traversing, save all the changes that need to happen into
590 // mReplacements, then do them by calling updateTree().
591 std::vector<NodeUpdateEntry> mReplacements;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400592};
593
594//
595// For traversing the tree, and computing max depth.
596// Takes a maximum depth limit to prevent stack overflow.
597//
598class TMaxDepthTraverser : public TIntermTraverser
599{
600 public:
601 POOL_ALLOCATOR_NEW_DELETE();
602 TMaxDepthTraverser(int depthLimit)
603 : TIntermTraverser(true, true, false, false),
604 mDepthLimit(depthLimit) { }
605
606 virtual bool visitBinary(Visit, TIntermBinary *) { return depthCheck(); }
607 virtual bool visitUnary(Visit, TIntermUnary *) { return depthCheck(); }
608 virtual bool visitSelection(Visit, TIntermSelection *) { return depthCheck(); }
609 virtual bool visitAggregate(Visit, TIntermAggregate *) { return depthCheck(); }
610 virtual bool visitLoop(Visit, TIntermLoop *) { return depthCheck(); }
611 virtual bool visitBranch(Visit, TIntermBranch *) { return depthCheck(); }
612
613protected:
614 bool depthCheck() const { return mMaxDepth < mDepthLimit; }
615
616 int mDepthLimit;
617};
618
Geoff Lang0a73dd82014-11-19 16:18:08 -0500619#endif // COMPILER_TRANSLATOR_INTERMNODE_H_