1 // Copyright 2016 The SwiftShader Authors. All Rights Reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //    http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 //
16 // Definition of the in-memory high-level intermediate representation
17 // of shaders.  This is a tree that parser creates.
18 //
19 // Nodes in the tree are defined as a hierarchy of classes derived from
20 // TIntermNode. Each is a node in a tree.  There is no preset branching factor;
21 // each node can have it's own type of list of children.
22 //
23 
24 #ifndef __INTERMEDIATE_H
25 #define __INTERMEDIATE_H
26 
27 #include "Common.h"
28 #include "Types.h"
29 #include "ConstantUnion.h"
30 
31 //
32 // Operators used by the high-level (parse tree) representation.
33 //
34 enum TOperator {
35 	EOpNull,            // if in a node, should only mean a node is still being built
36 	EOpSequence,        // denotes a list of statements, or parameters, etc.
37 	EOpFunctionCall,
38 	EOpFunction,        // For function definition
39 	EOpParameters,      // an aggregate listing the parameters to a function
40 
41 	EOpDeclaration,
42 	EOpInvariantDeclaration, // Specialized declarations for attributing invariance
43 	EOpPrototype,
44 
45 	//
46 	// Unary operators
47 	//
48 
49 	EOpNegative,
50 	EOpLogicalNot,
51 	EOpVectorLogicalNot,
52 	EOpBitwiseNot,
53 
54 	EOpPostIncrement,
55 	EOpPostDecrement,
56 	EOpPreIncrement,
57 	EOpPreDecrement,
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 	EOpOuterProduct,
78 	EOpTranspose,
79 	EOpDeterminant,
80 	EOpInverse,
81 
82 	EOpVectorTimesScalar,
83 	EOpVectorTimesMatrix,
84 	EOpMatrixTimesVector,
85 	EOpMatrixTimesScalar,
86 
87 	EOpLogicalOr,
88 	EOpLogicalXor,
89 	EOpLogicalAnd,
90 
91 	EOpIMod,
92 	EOpBitShiftLeft,
93 	EOpBitShiftRight,
94 	EOpBitwiseAnd,
95 	EOpBitwiseXor,
96 	EOpBitwiseOr,
97 
98 	EOpIndexDirect,
99 	EOpIndexIndirect,
100 	EOpIndexDirectStruct,
101 	EOpIndexDirectInterfaceBlock,
102 
103 	EOpVectorSwizzle,
104 
105 	//
106 	// Built-in functions potentially mapped to operators
107 	//
108 
109 	EOpRadians,
110 	EOpDegrees,
111 	EOpSin,
112 	EOpCos,
113 	EOpTan,
114 	EOpAsin,
115 	EOpAcos,
116 	EOpAtan,
117 	EOpSinh,
118 	EOpCosh,
119 	EOpTanh,
120 	EOpAsinh,
121 	EOpAcosh,
122 	EOpAtanh,
123 
124 	EOpPow,
125 	EOpExp,
126 	EOpLog,
127 	EOpExp2,
128 	EOpLog2,
129 	EOpSqrt,
130 	EOpInverseSqrt,
131 
132 	EOpAbs,
133 	EOpSign,
134 	EOpFloor,
135 	EOpTrunc,
136 	EOpRound,
137 	EOpRoundEven,
138 	EOpCeil,
139 	EOpFract,
140 	EOpMod,
141 	EOpModf,
142 	EOpMin,
143 	EOpMax,
144 	EOpClamp,
145 	EOpMix,
146 	EOpStep,
147 	EOpSmoothStep,
148 	EOpIsNan,
149 	EOpIsInf,
150 	EOpFloatBitsToInt,
151 	EOpFloatBitsToUint,
152 	EOpIntBitsToFloat,
153 	EOpUintBitsToFloat,
154 	EOpPackSnorm2x16,
155 	EOpPackUnorm2x16,
156 	EOpPackHalf2x16,
157 	EOpUnpackSnorm2x16,
158 	EOpUnpackUnorm2x16,
159 	EOpUnpackHalf2x16,
160 
161 	EOpLength,
162 	EOpDistance,
163 	EOpDot,
164 	EOpCross,
165 	EOpNormalize,
166 	EOpFaceForward,
167 	EOpReflect,
168 	EOpRefract,
169 
170 	EOpDFdx,            // Fragment only, OES_standard_derivatives extension
171 	EOpDFdy,            // Fragment only, OES_standard_derivatives extension
172 	EOpFwidth,          // Fragment only, OES_standard_derivatives extension
173 
174 	EOpMatrixTimesMatrix,
175 
176 	EOpAny,
177 	EOpAll,
178 
179 	//
180 	// Branch
181 	//
182 
183 	EOpKill,            // Fragment only
184 	EOpReturn,
185 	EOpBreak,
186 	EOpContinue,
187 
188 	//
189 	// Constructors
190 	//
191 
192 	EOpConstructInt,
193 	EOpConstructUInt,
194 	EOpConstructBool,
195 	EOpConstructFloat,
196 	EOpConstructVec2,
197 	EOpConstructVec3,
198 	EOpConstructVec4,
199 	EOpConstructBVec2,
200 	EOpConstructBVec3,
201 	EOpConstructBVec4,
202 	EOpConstructIVec2,
203 	EOpConstructIVec3,
204 	EOpConstructIVec4,
205 	EOpConstructUVec2,
206 	EOpConstructUVec3,
207 	EOpConstructUVec4,
208 	EOpConstructMat2,
209 	EOpConstructMat2x3,
210 	EOpConstructMat2x4,
211 	EOpConstructMat3x2,
212 	EOpConstructMat3,
213 	EOpConstructMat3x4,
214 	EOpConstructMat4x2,
215 	EOpConstructMat4x3,
216 	EOpConstructMat4,
217 	EOpConstructStruct,
218 
219 	//
220 	// moves
221 	//
222 
223 	EOpAssign,
224 	EOpInitialize,
225 	EOpAddAssign,
226 	EOpSubAssign,
227 	EOpMulAssign,
228 	EOpVectorTimesMatrixAssign,
229 	EOpVectorTimesScalarAssign,
230 	EOpMatrixTimesScalarAssign,
231 	EOpMatrixTimesMatrixAssign,
232 	EOpDivAssign,
233 	EOpIModAssign,
234 	EOpBitShiftLeftAssign,
235 	EOpBitShiftRightAssign,
236 	EOpBitwiseAndAssign,
237 	EOpBitwiseXorAssign,
238 	EOpBitwiseOrAssign
239 };
240 
241 extern TOperator TypeToConstructorOperator(const TType &type);
242 extern const char* getOperatorString(TOperator op);
243 
244 class TIntermTraverser;
245 class TIntermAggregate;
246 class TIntermBinary;
247 class TIntermUnary;
248 class TIntermConstantUnion;
249 class TIntermSelection;
250 class TIntermTyped;
251 class TIntermSymbol;
252 class TIntermLoop;
253 class TIntermBranch;
254 class TInfoSink;
255 class TIntermSwitch;
256 class TIntermCase;
257 
258 //
259 // Base class for the tree nodes
260 //
261 class TIntermNode {
262 public:
POOL_ALLOCATOR_NEW_DELETE()263 	POOL_ALLOCATOR_NEW_DELETE()
264 
265 	TIntermNode()
266 	{
267 		// TODO: Move this to TSourceLoc constructor
268 		// after getting rid of TPublicType.
269 		line.first_file = line.last_file = 0;
270 		line.first_line = line.last_line = 0;
271 	}
272 
getLine()273 	const TSourceLoc& getLine() const { return line; }
setLine(const TSourceLoc & l)274 	void setLine(const TSourceLoc& l) { line = l; }
275 
276 	virtual void traverse(TIntermTraverser*) = 0;
getAsTyped()277 	virtual TIntermTyped* getAsTyped() { return 0; }
getAsConstantUnion()278 	virtual TIntermConstantUnion* getAsConstantUnion() { return 0; }
getAsAggregate()279 	virtual TIntermAggregate* getAsAggregate() { return 0; }
getAsBinaryNode()280 	virtual TIntermBinary* getAsBinaryNode() { return 0; }
getAsUnaryNode()281 	virtual TIntermUnary* getAsUnaryNode() { return 0; }
getAsSelectionNode()282 	virtual TIntermSelection* getAsSelectionNode() { return 0; }
getAsSymbolNode()283 	virtual TIntermSymbol* getAsSymbolNode() { return 0; }
getAsLoopNode()284 	virtual TIntermLoop* getAsLoopNode() { return 0; }
getAsBranchNode()285 	virtual TIntermBranch* getAsBranchNode() { return 0; }
getAsSwitchNode()286 	virtual TIntermSwitch *getAsSwitchNode() { return 0; }
getAsCaseNode()287 	virtual TIntermCase *getAsCaseNode() { return 0; }
~TIntermNode()288 	virtual ~TIntermNode() { }
289 
290 protected:
291 	TSourceLoc line;
292 };
293 
294 //
295 // This is just to help yacc.
296 //
297 struct TIntermNodePair {
298 	TIntermNode* node1;
299 	TIntermNode* node2;
300 };
301 
302 //
303 // Intermediate class for nodes that have a type.
304 //
305 class TIntermTyped : public TIntermNode {
306 public:
TIntermTyped(const TType & t)307 	TIntermTyped(const TType& t) : type(t)  { }
getAsTyped()308 	virtual TIntermTyped* getAsTyped() { return this; }
309 
setType(const TType & t)310 	virtual void setType(const TType& t) { type = t; }
getType()311 	const TType& getType() const { return type; }
getTypePointer()312 	TType* getTypePointer() { return &type; }
313 
getBasicType()314 	TBasicType getBasicType() const { return type.getBasicType(); }
getQualifier()315 	TQualifier getQualifier() const { return type.getQualifier(); }
getPrecision()316 	TPrecision getPrecision() const { return type.getPrecision(); }
getNominalSize()317 	int getNominalSize() const { return type.getNominalSize(); }
getSecondarySize()318 	int getSecondarySize() const { return type.getSecondarySize(); }
319 
isInterfaceBlock()320 	bool isInterfaceBlock() const { return type.isInterfaceBlock(); }
isMatrix()321 	bool isMatrix() const { return type.isMatrix(); }
isArray()322 	bool isArray()  const { return type.isArray(); }
isVector()323 	bool isVector() const { return type.isVector(); }
isScalar()324 	bool isScalar() const { return type.isScalar(); }
isScalarInt()325 	bool isScalarInt() const { return type.isScalarInt(); }
isRegister()326 	bool isRegister() const { return type.isRegister(); }   // Fits in a 4-element register
isStruct()327 	bool isStruct() const { return type.isStruct(); }
getBasicString()328 	const char* getBasicString() const { return type.getBasicString(); }
getQualifierString()329 	const char* getQualifierString() const { return type.getQualifierString(); }
getCompleteString()330 	TString getCompleteString() const { return type.getCompleteString(); }
331 
totalRegisterCount()332 	int totalRegisterCount() const { return type.totalRegisterCount(); }
blockRegisterCount(bool samplersOnly)333 	int blockRegisterCount(bool samplersOnly) const { return samplersOnly ? type.totalSamplerRegisterCount() : type.blockRegisterCount(); }
elementRegisterCount()334 	int elementRegisterCount() const { return type.elementRegisterCount(); }
registerSize()335 	int registerSize() const { return type.registerSize(); }
getArraySize()336 	int getArraySize() const { return type.getArraySize(); }
337 
338 	static TIntermTyped *CreateIndexNode(int index);
339 protected:
340 	TType type;
341 };
342 
343 //
344 // Handle for, do-while, and while loops.
345 //
346 enum TLoopType {
347 	ELoopFor,
348 	ELoopWhile,
349 	ELoopDoWhile
350 };
351 
352 class TIntermLoop : public TIntermNode {
353 public:
TIntermLoop(TLoopType aType,TIntermNode * aInit,TIntermTyped * aCond,TIntermTyped * aExpr,TIntermNode * aBody)354 	TIntermLoop(TLoopType aType,
355 	            TIntermNode *aInit, TIntermTyped* aCond, TIntermTyped* aExpr,
356 	            TIntermNode* aBody) :
357 			type(aType),
358 			init(aInit),
359 			cond(aCond),
360 			expr(aExpr),
361 			body(aBody),
362 			unrollFlag(false) { }
363 
getAsLoopNode()364 	virtual TIntermLoop* getAsLoopNode() { return this; }
365 	virtual void traverse(TIntermTraverser*);
366 
getType()367 	TLoopType getType() const { return type; }
getInit()368 	TIntermNode* getInit() { return init; }
getCondition()369 	TIntermTyped* getCondition() { return cond; }
getExpression()370 	TIntermTyped* getExpression() { return expr; }
getBody()371 	TIntermNode* getBody() { return body; }
372 
setUnrollFlag(bool flag)373 	void setUnrollFlag(bool flag) { unrollFlag = flag; }
getUnrollFlag()374 	bool getUnrollFlag() { return unrollFlag; }
375 
376 protected:
377 	TLoopType type;
378 	TIntermNode* init;  // for-loop initialization
379 	TIntermTyped* cond; // loop exit condition
380 	TIntermTyped* expr; // for-loop expression
381 	TIntermNode* body;  // loop body
382 
383 	bool unrollFlag; // Whether the loop should be unrolled or not.
384 };
385 
386 //
387 // Handle break, continue, return, and kill.
388 //
389 class TIntermBranch : public TIntermNode {
390 public:
TIntermBranch(TOperator op,TIntermTyped * e)391 	TIntermBranch(TOperator op, TIntermTyped* e) :
392 			flowOp(op),
393 			expression(e) { }
394 
getAsBranchNode()395 	virtual TIntermBranch* getAsBranchNode() { return this; }
396 	virtual void traverse(TIntermTraverser*);
397 
getFlowOp()398 	TOperator getFlowOp() { return flowOp; }
getExpression()399 	TIntermTyped* getExpression() { return expression; }
400 
401 protected:
402 	TOperator flowOp;
403 	TIntermTyped* expression;  // non-zero except for "return exp;" statements
404 };
405 
406 //
407 // Nodes that correspond to symbols or constants in the source code.
408 //
409 class TIntermSymbol : public TIntermTyped {
410 public:
411 	// if symbol is initialized as symbol(sym), the memory comes from the poolallocator of sym. If sym comes from
412 	// per process globalpoolallocator, then it causes increased memory usage per compile
413 	// it is essential to use "symbol = sym" to assign to symbol
TIntermSymbol(int i,const TString & sym,const TType & t)414 	TIntermSymbol(int i, const TString& sym, const TType& t) :
415 			TIntermTyped(t), id(i)  { symbol = sym; }
416 
getId()417 	int getId() const { return id; }
getSymbol()418 	const TString& getSymbol() const { return symbol; }
419 
setId(int newId)420 	void setId(int newId) { id = newId; }
421 
422 	virtual void traverse(TIntermTraverser*);
getAsSymbolNode()423 	virtual TIntermSymbol* getAsSymbolNode() { return this; }
424 
425 protected:
426 	int id;
427 	TString symbol;
428 };
429 
430 class TIntermConstantUnion : public TIntermTyped {
431 public:
TIntermConstantUnion(ConstantUnion * unionPointer,const TType & t)432 	TIntermConstantUnion(ConstantUnion *unionPointer, const TType& t) : TIntermTyped(t), unionArrayPointer(unionPointer)
433 	{
434 		getTypePointer()->setQualifier(EvqConstExpr);
435 	}
436 
getUnionArrayPointer()437 	ConstantUnion* getUnionArrayPointer() const { return unionArrayPointer; }
438 
getIConst(int index)439 	int getIConst(int index) const { return unionArrayPointer ? unionArrayPointer[index].getIConst() : 0; }
getUConst(int index)440 	int getUConst(int index) const { return unionArrayPointer ? unionArrayPointer[index].getUConst() : 0; }
getFConst(int index)441 	float getFConst(int index) const { return unionArrayPointer ? unionArrayPointer[index].getFConst() : 0.0f; }
getBConst(int index)442 	bool getBConst(int index) const { return unionArrayPointer ? unionArrayPointer[index].getBConst() : false; }
443 
444 	// Previous union pointer freed on pool deallocation.
replaceConstantUnion(ConstantUnion * safeConstantUnion)445 	void replaceConstantUnion(ConstantUnion *safeConstantUnion) { unionArrayPointer = safeConstantUnion; }
446 
getAsConstantUnion()447 	virtual TIntermConstantUnion* getAsConstantUnion()  { return this; }
448 	virtual void traverse(TIntermTraverser*);
449 
450 	TIntermTyped* fold(TOperator, TIntermTyped*, TInfoSink&);
451 
452 protected:
453 	ConstantUnion *unionArrayPointer;
454 };
455 
456 //
457 // Intermediate class for node types that hold operators.
458 //
459 class TIntermOperator : public TIntermTyped {
460 public:
getOp()461 	TOperator getOp() const { return op; }
setOp(TOperator o)462 	void setOp(TOperator o) { op = o; }
463 
464 	bool modifiesState() const;
465 	bool isConstructor() const;
466 
467 protected:
TIntermOperator(TOperator o)468 	TIntermOperator(TOperator o) : TIntermTyped(TType(EbtFloat, EbpUndefined)), op(o) {}
TIntermOperator(TOperator o,TType & t)469 	TIntermOperator(TOperator o, TType& t) : TIntermTyped(t), op(o) {}
470 	TOperator op;
471 };
472 
473 //
474 // Nodes for all the basic binary math operators.
475 //
476 class TIntermBinary : public TIntermOperator {
477 public:
TIntermBinary(TOperator o)478 	TIntermBinary(TOperator o) : TIntermOperator(o) {}
479 
getAsBinaryNode()480 	TIntermBinary* getAsBinaryNode() override { return this; }
481 	void traverse(TIntermTraverser*) override;
482 
setType(const TType & t)483 	void setType(const TType &t) override
484 	{
485 		type = t;
486 
487 		if(left->getQualifier() == EvqConstExpr && right->getQualifier() == EvqConstExpr)
488 		{
489 			type.setQualifier(EvqConstExpr);
490 		}
491 	}
492 
setLeft(TIntermTyped * n)493 	void setLeft(TIntermTyped* n) { left = n; }
setRight(TIntermTyped * n)494 	void setRight(TIntermTyped* n) { right = n; }
getLeft()495 	TIntermTyped* getLeft() const { return left; }
getRight()496 	TIntermTyped* getRight() const { return right; }
497 	bool promote(TInfoSink&);
498 
499 protected:
500 	TIntermTyped* left;
501 	TIntermTyped* right;
502 };
503 
504 //
505 // Nodes for unary math operators.
506 //
507 class TIntermUnary : public TIntermOperator {
508 public:
TIntermUnary(TOperator o,TType & t)509 	TIntermUnary(TOperator o, TType& t) : TIntermOperator(o, t), operand(0) {}
TIntermUnary(TOperator o)510 	TIntermUnary(TOperator o) : TIntermOperator(o), operand(0) {}
511 
setType(const TType & t)512 	void setType(const TType &t) override
513 	{
514 		type = t;
515 
516 		if(operand->getQualifier() == EvqConstExpr)
517 		{
518 			type.setQualifier(EvqConstExpr);
519 		}
520 	}
521 
522 	void traverse(TIntermTraverser*) override;
getAsUnaryNode()523 	TIntermUnary* getAsUnaryNode() override { return this; }
524 
setOperand(TIntermTyped * o)525 	void setOperand(TIntermTyped* o) { operand = o; }
getOperand()526 	TIntermTyped* getOperand() { return operand; }
527 	bool promote(TInfoSink&, const TType *funcReturnType);
528 
529 protected:
530 	TIntermTyped* operand;
531 };
532 
533 typedef TVector<TIntermNode*> TIntermSequence;
534 typedef TVector<int> TQualifierList;
535 
536 //
537 // Nodes that operate on an arbitrary sized set of children.
538 //
539 class TIntermAggregate : public TIntermOperator {
540 public:
TIntermAggregate()541 	TIntermAggregate() : TIntermOperator(EOpNull), userDefined(false) { endLine = { 0, 0, 0, 0 }; }
TIntermAggregate(TOperator o)542 	TIntermAggregate(TOperator o) : TIntermOperator(o), userDefined(false) { endLine = { 0, 0, 0, 0 }; }
~TIntermAggregate()543 	~TIntermAggregate() { }
544 
getAsAggregate()545 	TIntermAggregate* getAsAggregate() override { return this; }
546 	void traverse(TIntermTraverser*) override;
547 
getSequence()548 	TIntermSequence& getSequence() { return sequence; }
549 
setType(const TType & t)550 	void setType(const TType &t) override
551 	{
552 		type = t;
553 
554 		if(op != EOpFunctionCall)
555 		{
556 			for(TIntermNode *node : sequence)
557 			{
558 				if(!node->getAsTyped() || node->getAsTyped()->getQualifier() != EvqConstExpr)
559 				{
560 					return;
561 				}
562 			}
563 
564 			type.setQualifier(EvqConstExpr);
565 		}
566 	}
567 
setName(const TString & n)568 	void setName(const TString& n) { name = n; }
getName()569 	const TString& getName() const { return name; }
570 
setUserDefined()571 	void setUserDefined() { userDefined = true; }
isUserDefined()572 	bool isUserDefined() const { return userDefined; }
573 
setOptimize(bool o)574 	void setOptimize(bool o) { optimize = o; }
getOptimize()575 	bool getOptimize() { return optimize; }
setDebug(bool d)576 	void setDebug(bool d) { debug = d; }
getDebug()577 	bool getDebug() { return debug; }
578 
setEndLine(const TSourceLoc & line)579 	void setEndLine(const TSourceLoc& line) { endLine = line; }
getEndLine()580 	const TSourceLoc& getEndLine() const { return endLine; }
581 
isConstantFoldable()582 	bool isConstantFoldable()
583 	{
584 		for(TIntermNode *node : sequence)
585 		{
586 			if(!node->getAsConstantUnion() || !node->getAsConstantUnion()->getUnionArrayPointer())
587 			{
588 				return false;
589 			}
590 		}
591 
592 		return true;
593 	}
594 
595 protected:
596 	TIntermAggregate(const TIntermAggregate&); // disallow copy constructor
597 	TIntermAggregate& operator=(const TIntermAggregate&); // disallow assignment operator
598 	TIntermSequence sequence;
599 	TString name;
600 	bool userDefined; // used for user defined function names
601 
602 	bool optimize;
603 	bool debug;
604 	TSourceLoc endLine;
605 };
606 
607 //
608 // For if tests.  Simplified since there is no switch statement.
609 //
610 class TIntermSelection : public TIntermTyped {
611 public:
TIntermSelection(TIntermTyped * cond,TIntermNode * trueB,TIntermNode * falseB)612 	TIntermSelection(TIntermTyped* cond, TIntermNode* trueB, TIntermNode* falseB) :
613 			TIntermTyped(TType(EbtVoid, EbpUndefined)), condition(cond), trueBlock(trueB), falseBlock(falseB) {}
TIntermSelection(TIntermTyped * cond,TIntermNode * trueB,TIntermNode * falseB,const TType & type)614 	TIntermSelection(TIntermTyped* cond, TIntermNode* trueB, TIntermNode* falseB, const TType& type) :
615 			TIntermTyped(type), condition(cond), trueBlock(trueB), falseBlock(falseB)
616 	{
617 		this->type.setQualifier(EvqTemporary);
618 	}
619 
620 	virtual void traverse(TIntermTraverser*);
621 
usesTernaryOperator()622 	bool usesTernaryOperator() const { return getBasicType() != EbtVoid; }
getCondition()623 	TIntermTyped* getCondition() const { return condition; }
getTrueBlock()624 	TIntermNode* getTrueBlock() const { return trueBlock; }
getFalseBlock()625 	TIntermNode* getFalseBlock() const { return falseBlock; }
getAsSelectionNode()626 	TIntermSelection* getAsSelectionNode() { return this; }
627 
628 protected:
629 	TIntermTyped* condition;
630 	TIntermNode* trueBlock;
631 	TIntermNode* falseBlock;
632 };
633 
634 //
635 // Switch statement.
636 //
637 class TIntermSwitch : public TIntermNode
638 {
639 public:
TIntermSwitch(TIntermTyped * init,TIntermAggregate * statementList)640 	TIntermSwitch(TIntermTyped *init, TIntermAggregate *statementList)
641 		: TIntermNode(), mInit(init), mStatementList(statementList)
642 	{}
643 
644 	void traverse(TIntermTraverser *it);
645 
getAsSwitchNode()646 	TIntermSwitch *getAsSwitchNode() { return this; }
647 
getInit()648 	TIntermTyped *getInit() { return mInit; }
getStatementList()649 	TIntermAggregate *getStatementList() { return mStatementList; }
setStatementList(TIntermAggregate * statementList)650 	void setStatementList(TIntermAggregate *statementList) { mStatementList = statementList; }
651 
652 protected:
653 	TIntermTyped *mInit;
654 	TIntermAggregate *mStatementList;
655 };
656 
657 //
658 // Case label.
659 //
660 class TIntermCase : public TIntermNode
661 {
662 public:
TIntermCase(TIntermTyped * condition)663 	TIntermCase(TIntermTyped *condition)
664 		: TIntermNode(), mCondition(condition)
665 	{}
666 
667 	void traverse(TIntermTraverser *it);
668 
getAsCaseNode()669 	TIntermCase *getAsCaseNode() { return this; }
670 
hasCondition()671 	bool hasCondition() const { return mCondition != nullptr; }
getCondition()672 	TIntermTyped *getCondition() const { return mCondition; }
673 
674 protected:
675 	TIntermTyped *mCondition;
676 };
677 
678 enum Visit
679 {
680 	PreVisit,
681 	InVisit,
682 	PostVisit
683 };
684 
685 //
686 // For traversing the tree.  User should derive from this,
687 // put their traversal specific data in it, and then pass
688 // it to a Traverse method.
689 //
690 // When using this, just fill in the methods for nodes you want visited.
691 // Return false from a pre-visit to skip visiting that node's subtree.
692 //
693 class TIntermTraverser
694 {
695 public:
POOL_ALLOCATOR_NEW_DELETE()696 	POOL_ALLOCATOR_NEW_DELETE()
697 	TIntermTraverser(bool preVisit = true, bool inVisit = false, bool postVisit = false, bool rightToLeft = false) :
698 			preVisit(preVisit),
699 			inVisit(inVisit),
700 			postVisit(postVisit),
701 			rightToLeft(rightToLeft),
702 			mDepth(0) {}
~TIntermTraverser()703 	virtual ~TIntermTraverser() {}
704 
visitSymbol(TIntermSymbol *)705 	virtual void visitSymbol(TIntermSymbol*) {}
visitConstantUnion(TIntermConstantUnion *)706 	virtual void visitConstantUnion(TIntermConstantUnion*) {}
visitBinary(Visit visit,TIntermBinary *)707 	virtual bool visitBinary(Visit visit, TIntermBinary*) {return true;}
visitUnary(Visit visit,TIntermUnary *)708 	virtual bool visitUnary(Visit visit, TIntermUnary*) {return true;}
visitSelection(Visit visit,TIntermSelection *)709 	virtual bool visitSelection(Visit visit, TIntermSelection*) {return true;}
visitAggregate(Visit visit,TIntermAggregate *)710 	virtual bool visitAggregate(Visit visit, TIntermAggregate*) {return true;}
visitLoop(Visit visit,TIntermLoop *)711 	virtual bool visitLoop(Visit visit, TIntermLoop*) {return true;}
visitBranch(Visit visit,TIntermBranch *)712 	virtual bool visitBranch(Visit visit, TIntermBranch*) {return true;}
visitSwitch(Visit,TIntermSwitch *)713 	virtual bool visitSwitch(Visit, TIntermSwitch*) { return true; }
visitCase(Visit,TIntermCase *)714 	virtual bool visitCase(Visit, TIntermCase*) { return true; }
715 
incrementDepth(TIntermNode * current)716 	void incrementDepth(TIntermNode *current)
717 	{
718 		mDepth++;
719 		mPath.push_back(current);
720 	}
721 
decrementDepth()722 	void decrementDepth()
723 	{
724 		mDepth--;
725 		mPath.pop_back();
726 	}
727 
getParentNode()728 	TIntermNode *getParentNode()
729 	{
730 		return mPath.size() == 0 ? nullptr : mPath.back();
731 	}
732 
733 	const bool preVisit;
734 	const bool inVisit;
735 	const bool postVisit;
736 	const bool rightToLeft;
737 
738 protected:
739 	int mDepth;
740 
741 	// All the nodes from root to the current node's parent during traversing.
742 	TVector<TIntermNode *> mPath;
743 
744 private:
745 	struct ParentBlock
746 	{
ParentBlockParentBlock747 		ParentBlock(TIntermAggregate *nodeIn, TIntermSequence::size_type posIn)
748 		: node(nodeIn), pos(posIn)
749 		{}
750 
751 		TIntermAggregate *node;
752 		TIntermSequence::size_type pos;
753 	};
754 	// All the code blocks from the root to the current node's parent during traversal.
755 	std::vector<ParentBlock> mParentBlockStack;
756 };
757 
758 #endif // __INTERMEDIATE_H
759