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