|
1 // |
|
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. |
|
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 |
|
16 #ifndef __INTERMEDIATE_H |
|
17 #define __INTERMEDIATE_H |
|
18 |
|
19 #include "GLSLANG/ShaderLang.h" |
|
20 |
|
21 #include <algorithm> |
|
22 #include "compiler/Common.h" |
|
23 #include "compiler/Types.h" |
|
24 #include "compiler/ConstantUnion.h" |
|
25 |
|
26 // |
|
27 // Operators used by the high-level (parse tree) representation. |
|
28 // |
|
29 enum TOperator { |
|
30 EOpNull, // if in a node, should only mean a node is still being built |
|
31 EOpSequence, // denotes a list of statements, or parameters, etc. |
|
32 EOpFunctionCall, |
|
33 EOpFunction, // For function definition |
|
34 EOpParameters, // an aggregate listing the parameters to a function |
|
35 |
|
36 EOpDeclaration, |
|
37 EOpPrototype, |
|
38 |
|
39 // |
|
40 // Unary operators |
|
41 // |
|
42 |
|
43 EOpNegative, |
|
44 EOpLogicalNot, |
|
45 EOpVectorLogicalNot, |
|
46 |
|
47 EOpPostIncrement, |
|
48 EOpPostDecrement, |
|
49 EOpPreIncrement, |
|
50 EOpPreDecrement, |
|
51 |
|
52 EOpConvIntToBool, |
|
53 EOpConvFloatToBool, |
|
54 EOpConvBoolToFloat, |
|
55 EOpConvIntToFloat, |
|
56 EOpConvFloatToInt, |
|
57 EOpConvBoolToInt, |
|
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 EOpVectorTimesScalar, |
|
78 EOpVectorTimesMatrix, |
|
79 EOpMatrixTimesVector, |
|
80 EOpMatrixTimesScalar, |
|
81 |
|
82 EOpLogicalOr, |
|
83 EOpLogicalXor, |
|
84 EOpLogicalAnd, |
|
85 |
|
86 EOpIndexDirect, |
|
87 EOpIndexIndirect, |
|
88 EOpIndexDirectStruct, |
|
89 |
|
90 EOpVectorSwizzle, |
|
91 |
|
92 // |
|
93 // Built-in functions potentially mapped to operators |
|
94 // |
|
95 |
|
96 EOpRadians, |
|
97 EOpDegrees, |
|
98 EOpSin, |
|
99 EOpCos, |
|
100 EOpTan, |
|
101 EOpAsin, |
|
102 EOpAcos, |
|
103 EOpAtan, |
|
104 |
|
105 EOpPow, |
|
106 EOpExp, |
|
107 EOpLog, |
|
108 EOpExp2, |
|
109 EOpLog2, |
|
110 EOpSqrt, |
|
111 EOpInverseSqrt, |
|
112 |
|
113 EOpAbs, |
|
114 EOpSign, |
|
115 EOpFloor, |
|
116 EOpCeil, |
|
117 EOpFract, |
|
118 EOpMod, |
|
119 EOpMin, |
|
120 EOpMax, |
|
121 EOpClamp, |
|
122 EOpMix, |
|
123 EOpStep, |
|
124 EOpSmoothStep, |
|
125 |
|
126 EOpLength, |
|
127 EOpDistance, |
|
128 EOpDot, |
|
129 EOpCross, |
|
130 EOpNormalize, |
|
131 EOpFaceForward, |
|
132 EOpReflect, |
|
133 EOpRefract, |
|
134 |
|
135 EOpDFdx, // Fragment only, OES_standard_derivatives extension |
|
136 EOpDFdy, // Fragment only, OES_standard_derivatives extension |
|
137 EOpFwidth, // Fragment only, OES_standard_derivatives extension |
|
138 |
|
139 EOpMatrixTimesMatrix, |
|
140 |
|
141 EOpAny, |
|
142 EOpAll, |
|
143 |
|
144 // |
|
145 // Branch |
|
146 // |
|
147 |
|
148 EOpKill, // Fragment only |
|
149 EOpReturn, |
|
150 EOpBreak, |
|
151 EOpContinue, |
|
152 |
|
153 // |
|
154 // Constructors |
|
155 // |
|
156 |
|
157 EOpConstructInt, |
|
158 EOpConstructBool, |
|
159 EOpConstructFloat, |
|
160 EOpConstructVec2, |
|
161 EOpConstructVec3, |
|
162 EOpConstructVec4, |
|
163 EOpConstructBVec2, |
|
164 EOpConstructBVec3, |
|
165 EOpConstructBVec4, |
|
166 EOpConstructIVec2, |
|
167 EOpConstructIVec3, |
|
168 EOpConstructIVec4, |
|
169 EOpConstructMat2, |
|
170 EOpConstructMat3, |
|
171 EOpConstructMat4, |
|
172 EOpConstructStruct, |
|
173 |
|
174 // |
|
175 // moves |
|
176 // |
|
177 |
|
178 EOpAssign, |
|
179 EOpInitialize, |
|
180 EOpAddAssign, |
|
181 EOpSubAssign, |
|
182 EOpMulAssign, |
|
183 EOpVectorTimesMatrixAssign, |
|
184 EOpVectorTimesScalarAssign, |
|
185 EOpMatrixTimesScalarAssign, |
|
186 EOpMatrixTimesMatrixAssign, |
|
187 EOpDivAssign |
|
188 }; |
|
189 |
|
190 extern const char* getOperatorString(TOperator op); |
|
191 |
|
192 class TIntermTraverser; |
|
193 class TIntermAggregate; |
|
194 class TIntermBinary; |
|
195 class TIntermUnary; |
|
196 class TIntermConstantUnion; |
|
197 class TIntermSelection; |
|
198 class TIntermTyped; |
|
199 class TIntermSymbol; |
|
200 class TIntermLoop; |
|
201 class TInfoSink; |
|
202 |
|
203 // |
|
204 // Base class for the tree nodes |
|
205 // |
|
206 class TIntermNode { |
|
207 public: |
|
208 POOL_ALLOCATOR_NEW_DELETE(); |
|
209 TIntermNode() { |
|
210 // TODO: Move this to TSourceLoc constructor |
|
211 // after getting rid of TPublicType. |
|
212 line.first_file = line.last_file = 0; |
|
213 line.first_line = line.last_line = 0; |
|
214 } |
|
215 virtual ~TIntermNode() { } |
|
216 |
|
217 const TSourceLoc& getLine() const { return line; } |
|
218 void setLine(const TSourceLoc& l) { line = l; } |
|
219 |
|
220 virtual void traverse(TIntermTraverser*) = 0; |
|
221 virtual TIntermTyped* getAsTyped() { return 0; } |
|
222 virtual TIntermConstantUnion* getAsConstantUnion() { return 0; } |
|
223 virtual TIntermAggregate* getAsAggregate() { return 0; } |
|
224 virtual TIntermBinary* getAsBinaryNode() { return 0; } |
|
225 virtual TIntermUnary* getAsUnaryNode() { return 0; } |
|
226 virtual TIntermSelection* getAsSelectionNode() { return 0; } |
|
227 virtual TIntermSymbol* getAsSymbolNode() { return 0; } |
|
228 virtual TIntermLoop* getAsLoopNode() { return 0; } |
|
229 |
|
230 protected: |
|
231 TSourceLoc line; |
|
232 }; |
|
233 |
|
234 // |
|
235 // This is just to help yacc. |
|
236 // |
|
237 struct TIntermNodePair { |
|
238 TIntermNode* node1; |
|
239 TIntermNode* node2; |
|
240 }; |
|
241 |
|
242 // |
|
243 // Intermediate class for nodes that have a type. |
|
244 // |
|
245 class TIntermTyped : public TIntermNode { |
|
246 public: |
|
247 TIntermTyped(const TType& t) : type(t) { } |
|
248 virtual TIntermTyped* getAsTyped() { return this; } |
|
249 |
|
250 void setType(const TType& t) { type = t; } |
|
251 const TType& getType() const { return type; } |
|
252 TType* getTypePointer() { return &type; } |
|
253 |
|
254 TBasicType getBasicType() const { return type.getBasicType(); } |
|
255 TQualifier getQualifier() const { return type.getQualifier(); } |
|
256 TPrecision getPrecision() const { return type.getPrecision(); } |
|
257 int getNominalSize() const { return type.getNominalSize(); } |
|
258 |
|
259 bool isMatrix() const { return type.isMatrix(); } |
|
260 bool isArray() const { return type.isArray(); } |
|
261 bool isVector() const { return type.isVector(); } |
|
262 bool isScalar() const { return type.isScalar(); } |
|
263 const char* getBasicString() const { return type.getBasicString(); } |
|
264 const char* getQualifierString() const { return type.getQualifierString(); } |
|
265 TString getCompleteString() const { return type.getCompleteString(); } |
|
266 |
|
267 int totalRegisterCount() const { return type.totalRegisterCount(); } |
|
268 int elementRegisterCount() const { return type.elementRegisterCount(); } |
|
269 int getArraySize() const { return type.getArraySize(); } |
|
270 |
|
271 protected: |
|
272 TType type; |
|
273 }; |
|
274 |
|
275 // |
|
276 // Handle for, do-while, and while loops. |
|
277 // |
|
278 enum TLoopType { |
|
279 ELoopFor, |
|
280 ELoopWhile, |
|
281 ELoopDoWhile |
|
282 }; |
|
283 |
|
284 class TIntermLoop : public TIntermNode { |
|
285 public: |
|
286 TIntermLoop(TLoopType aType, |
|
287 TIntermNode *aInit, TIntermTyped* aCond, TIntermTyped* aExpr, |
|
288 TIntermNode* aBody) : |
|
289 type(aType), |
|
290 init(aInit), |
|
291 cond(aCond), |
|
292 expr(aExpr), |
|
293 body(aBody), |
|
294 unrollFlag(false) { } |
|
295 |
|
296 virtual TIntermLoop* getAsLoopNode() { return this; } |
|
297 virtual void traverse(TIntermTraverser*); |
|
298 |
|
299 TLoopType getType() const { return type; } |
|
300 TIntermNode* getInit() { return init; } |
|
301 TIntermTyped* getCondition() { return cond; } |
|
302 TIntermTyped* getExpression() { return expr; } |
|
303 TIntermNode* getBody() { return body; } |
|
304 |
|
305 void setUnrollFlag(bool flag) { unrollFlag = flag; } |
|
306 bool getUnrollFlag() { return unrollFlag; } |
|
307 |
|
308 protected: |
|
309 TLoopType type; |
|
310 TIntermNode* init; // for-loop initialization |
|
311 TIntermTyped* cond; // loop exit condition |
|
312 TIntermTyped* expr; // for-loop expression |
|
313 TIntermNode* body; // loop body |
|
314 |
|
315 bool unrollFlag; // Whether the loop should be unrolled or not. |
|
316 }; |
|
317 |
|
318 // |
|
319 // Handle break, continue, return, and kill. |
|
320 // |
|
321 class TIntermBranch : public TIntermNode { |
|
322 public: |
|
323 TIntermBranch(TOperator op, TIntermTyped* e) : |
|
324 flowOp(op), |
|
325 expression(e) { } |
|
326 |
|
327 virtual void traverse(TIntermTraverser*); |
|
328 |
|
329 TOperator getFlowOp() { return flowOp; } |
|
330 TIntermTyped* getExpression() { return expression; } |
|
331 |
|
332 protected: |
|
333 TOperator flowOp; |
|
334 TIntermTyped* expression; // non-zero except for "return exp;" statements |
|
335 }; |
|
336 |
|
337 // |
|
338 // Nodes that correspond to symbols or constants in the source code. |
|
339 // |
|
340 class TIntermSymbol : public TIntermTyped { |
|
341 public: |
|
342 // if symbol is initialized as symbol(sym), the memory comes from the poolallocator of sym. If sym comes from |
|
343 // per process globalpoolallocator, then it causes increased memory usage per compile |
|
344 // it is essential to use "symbol = sym" to assign to symbol |
|
345 TIntermSymbol(int i, const TString& sym, const TType& t) : |
|
346 TIntermTyped(t), id(i) { symbol = sym; originalSymbol = sym; } |
|
347 |
|
348 int getId() const { return id; } |
|
349 const TString& getSymbol() const { return symbol; } |
|
350 |
|
351 void setId(int newId) { id = newId; } |
|
352 void setSymbol(const TString& sym) { symbol = sym; } |
|
353 |
|
354 const TString& getOriginalSymbol() const { return originalSymbol; } |
|
355 |
|
356 virtual void traverse(TIntermTraverser*); |
|
357 virtual TIntermSymbol* getAsSymbolNode() { return this; } |
|
358 |
|
359 protected: |
|
360 int id; |
|
361 TString symbol; |
|
362 TString originalSymbol; |
|
363 }; |
|
364 |
|
365 class TIntermConstantUnion : public TIntermTyped { |
|
366 public: |
|
367 TIntermConstantUnion(ConstantUnion *unionPointer, const TType& t) : TIntermTyped(t), unionArrayPointer(unionPointer) { } |
|
368 |
|
369 ConstantUnion* getUnionArrayPointer() const { return unionArrayPointer; } |
|
370 |
|
371 int getIConst(int index) const { return unionArrayPointer ? unionArrayPointer[index].getIConst() : 0; } |
|
372 float getFConst(int index) const { return unionArrayPointer ? unionArrayPointer[index].getFConst() : 0.0f; } |
|
373 bool getBConst(int index) const { return unionArrayPointer ? unionArrayPointer[index].getBConst() : false; } |
|
374 |
|
375 virtual TIntermConstantUnion* getAsConstantUnion() { return this; } |
|
376 virtual void traverse(TIntermTraverser*); |
|
377 |
|
378 TIntermTyped* fold(TOperator, TIntermTyped*, TInfoSink&); |
|
379 |
|
380 protected: |
|
381 ConstantUnion *unionArrayPointer; |
|
382 }; |
|
383 |
|
384 // |
|
385 // Intermediate class for node types that hold operators. |
|
386 // |
|
387 class TIntermOperator : public TIntermTyped { |
|
388 public: |
|
389 TOperator getOp() const { return op; } |
|
390 void setOp(TOperator o) { op = o; } |
|
391 |
|
392 bool modifiesState() const; |
|
393 bool isConstructor() const; |
|
394 |
|
395 protected: |
|
396 TIntermOperator(TOperator o) : TIntermTyped(TType(EbtFloat, EbpUndefined)), op(o) {} |
|
397 TIntermOperator(TOperator o, TType& t) : TIntermTyped(t), op(o) {} |
|
398 TOperator op; |
|
399 }; |
|
400 |
|
401 // |
|
402 // Nodes for all the basic binary math operators. |
|
403 // |
|
404 class TIntermBinary : public TIntermOperator { |
|
405 public: |
|
406 TIntermBinary(TOperator o) : TIntermOperator(o), addIndexClamp(false) {} |
|
407 |
|
408 virtual TIntermBinary* getAsBinaryNode() { return this; } |
|
409 virtual void traverse(TIntermTraverser*); |
|
410 |
|
411 void setLeft(TIntermTyped* n) { left = n; } |
|
412 void setRight(TIntermTyped* n) { right = n; } |
|
413 TIntermTyped* getLeft() const { return left; } |
|
414 TIntermTyped* getRight() const { return right; } |
|
415 bool promote(TInfoSink&); |
|
416 |
|
417 void setAddIndexClamp() { addIndexClamp = true; } |
|
418 bool getAddIndexClamp() { return addIndexClamp; } |
|
419 |
|
420 protected: |
|
421 TIntermTyped* left; |
|
422 TIntermTyped* right; |
|
423 |
|
424 // If set to true, wrap any EOpIndexIndirect with a clamp to bounds. |
|
425 bool addIndexClamp; |
|
426 }; |
|
427 |
|
428 // |
|
429 // Nodes for unary math operators. |
|
430 // |
|
431 class TIntermUnary : public TIntermOperator { |
|
432 public: |
|
433 TIntermUnary(TOperator o, TType& t) : TIntermOperator(o, t), operand(0), useEmulatedFunction(false) {} |
|
434 TIntermUnary(TOperator o) : TIntermOperator(o), operand(0), useEmulatedFunction(false) {} |
|
435 |
|
436 virtual void traverse(TIntermTraverser*); |
|
437 virtual TIntermUnary* getAsUnaryNode() { return this; } |
|
438 |
|
439 void setOperand(TIntermTyped* o) { operand = o; } |
|
440 TIntermTyped* getOperand() { return operand; } |
|
441 bool promote(TInfoSink&); |
|
442 |
|
443 void setUseEmulatedFunction() { useEmulatedFunction = true; } |
|
444 bool getUseEmulatedFunction() { return useEmulatedFunction; } |
|
445 |
|
446 protected: |
|
447 TIntermTyped* operand; |
|
448 |
|
449 // If set to true, replace the built-in function call with an emulated one |
|
450 // to work around driver bugs. |
|
451 bool useEmulatedFunction; |
|
452 }; |
|
453 |
|
454 typedef TVector<TIntermNode*> TIntermSequence; |
|
455 typedef TVector<int> TQualifierList; |
|
456 |
|
457 // |
|
458 // Nodes that operate on an arbitrary sized set of children. |
|
459 // |
|
460 class TIntermAggregate : public TIntermOperator { |
|
461 public: |
|
462 TIntermAggregate() : TIntermOperator(EOpNull), userDefined(false), useEmulatedFunction(false) { } |
|
463 TIntermAggregate(TOperator o) : TIntermOperator(o), useEmulatedFunction(false) { } |
|
464 ~TIntermAggregate() { } |
|
465 |
|
466 virtual TIntermAggregate* getAsAggregate() { return this; } |
|
467 virtual void traverse(TIntermTraverser*); |
|
468 |
|
469 TIntermSequence& getSequence() { return sequence; } |
|
470 |
|
471 void setName(const TString& n) { name = n; } |
|
472 const TString& getName() const { return name; } |
|
473 |
|
474 void setUserDefined() { userDefined = true; } |
|
475 bool isUserDefined() const { return userDefined; } |
|
476 |
|
477 void setOptimize(bool o) { optimize = o; } |
|
478 bool getOptimize() { return optimize; } |
|
479 void setDebug(bool d) { debug = d; } |
|
480 bool getDebug() { return debug; } |
|
481 |
|
482 void setUseEmulatedFunction() { useEmulatedFunction = true; } |
|
483 bool getUseEmulatedFunction() { return useEmulatedFunction; } |
|
484 |
|
485 protected: |
|
486 TIntermAggregate(const TIntermAggregate&); // disallow copy constructor |
|
487 TIntermAggregate& operator=(const TIntermAggregate&); // disallow assignment operator |
|
488 TIntermSequence sequence; |
|
489 TString name; |
|
490 bool userDefined; // used for user defined function names |
|
491 |
|
492 bool optimize; |
|
493 bool debug; |
|
494 |
|
495 // If set to true, replace the built-in function call with an emulated one |
|
496 // to work around driver bugs. |
|
497 bool useEmulatedFunction; |
|
498 }; |
|
499 |
|
500 // |
|
501 // For if tests. Simplified since there is no switch statement. |
|
502 // |
|
503 class TIntermSelection : public TIntermTyped { |
|
504 public: |
|
505 TIntermSelection(TIntermTyped* cond, TIntermNode* trueB, TIntermNode* falseB) : |
|
506 TIntermTyped(TType(EbtVoid, EbpUndefined)), condition(cond), trueBlock(trueB), falseBlock(falseB) {} |
|
507 TIntermSelection(TIntermTyped* cond, TIntermNode* trueB, TIntermNode* falseB, const TType& type) : |
|
508 TIntermTyped(type), condition(cond), trueBlock(trueB), falseBlock(falseB) {} |
|
509 |
|
510 virtual void traverse(TIntermTraverser*); |
|
511 |
|
512 bool usesTernaryOperator() const { return getBasicType() != EbtVoid; } |
|
513 TIntermNode* getCondition() const { return condition; } |
|
514 TIntermNode* getTrueBlock() const { return trueBlock; } |
|
515 TIntermNode* getFalseBlock() const { return falseBlock; } |
|
516 TIntermSelection* getAsSelectionNode() { return this; } |
|
517 |
|
518 protected: |
|
519 TIntermTyped* condition; |
|
520 TIntermNode* trueBlock; |
|
521 TIntermNode* falseBlock; |
|
522 }; |
|
523 |
|
524 enum Visit |
|
525 { |
|
526 PreVisit, |
|
527 InVisit, |
|
528 PostVisit |
|
529 }; |
|
530 |
|
531 // |
|
532 // For traversing the tree. User should derive from this, |
|
533 // put their traversal specific data in it, and then pass |
|
534 // it to a Traverse method. |
|
535 // |
|
536 // When using this, just fill in the methods for nodes you want visited. |
|
537 // Return false from a pre-visit to skip visiting that node's subtree. |
|
538 // |
|
539 class TIntermTraverser |
|
540 { |
|
541 public: |
|
542 POOL_ALLOCATOR_NEW_DELETE(); |
|
543 TIntermTraverser(bool preVisit = true, bool inVisit = false, bool postVisit = false, bool rightToLeft = false) : |
|
544 preVisit(preVisit), |
|
545 inVisit(inVisit), |
|
546 postVisit(postVisit), |
|
547 rightToLeft(rightToLeft), |
|
548 depth(0), |
|
549 maxDepth(0) {} |
|
550 virtual ~TIntermTraverser() {}; |
|
551 |
|
552 virtual void visitSymbol(TIntermSymbol*) {} |
|
553 virtual void visitConstantUnion(TIntermConstantUnion*) {} |
|
554 virtual bool visitBinary(Visit visit, TIntermBinary*) {return true;} |
|
555 virtual bool visitUnary(Visit visit, TIntermUnary*) {return true;} |
|
556 virtual bool visitSelection(Visit visit, TIntermSelection*) {return true;} |
|
557 virtual bool visitAggregate(Visit visit, TIntermAggregate*) {return true;} |
|
558 virtual bool visitLoop(Visit visit, TIntermLoop*) {return true;} |
|
559 virtual bool visitBranch(Visit visit, TIntermBranch*) {return true;} |
|
560 |
|
561 int getMaxDepth() const {return maxDepth;} |
|
562 void incrementDepth() {depth++; maxDepth = std::max(maxDepth, depth); } |
|
563 void decrementDepth() {depth--;} |
|
564 |
|
565 // Return the original name if hash function pointer is NULL; |
|
566 // otherwise return the hashed name. |
|
567 static TString hash(const TString& name, ShHashFunction64 hashFunction); |
|
568 |
|
569 const bool preVisit; |
|
570 const bool inVisit; |
|
571 const bool postVisit; |
|
572 const bool rightToLeft; |
|
573 |
|
574 protected: |
|
575 int depth; |
|
576 int maxDepth; |
|
577 }; |
|
578 |
|
579 #endif // __INTERMEDIATE_H |