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