1 | // |
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 | |
16 | #ifndef COMPILER_TRANSLATOR_INTERMNODE_H_ |
17 | #define COMPILER_TRANSLATOR_INTERMNODE_H_ |
18 | |
19 | #include "GLSLANG/ShaderLang.h" |
20 | |
21 | #include <algorithm> |
22 | #include <queue> |
23 | |
24 | #include "common/angleutils.h" |
25 | #include "compiler/translator/Common.h" |
26 | #include "compiler/translator/ConstantUnion.h" |
27 | #include "compiler/translator/ImmutableString.h" |
28 | #include "compiler/translator/Operator.h" |
29 | #include "compiler/translator/SymbolUniqueId.h" |
30 | #include "compiler/translator/Types.h" |
31 | #include "compiler/translator/tree_util/Visit.h" |
32 | |
33 | namespace sh |
34 | { |
35 | |
36 | class TDiagnostics; |
37 | |
38 | class TIntermTraverser; |
39 | class TIntermAggregate; |
40 | class TIntermBlock; |
41 | class TIntermInvariantDeclaration; |
42 | class TIntermDeclaration; |
43 | class TIntermFunctionPrototype; |
44 | class TIntermFunctionDefinition; |
45 | class TIntermSwizzle; |
46 | class TIntermBinary; |
47 | class TIntermUnary; |
48 | class TIntermConstantUnion; |
49 | class TIntermTernary; |
50 | class TIntermIfElse; |
51 | class TIntermSwitch; |
52 | class TIntermCase; |
53 | class TIntermTyped; |
54 | class TIntermSymbol; |
55 | class TIntermLoop; |
56 | class TInfoSink; |
57 | class TInfoSinkBase; |
58 | class TIntermBranch; |
59 | class TIntermPreprocessorDirective; |
60 | |
61 | class TSymbolTable; |
62 | class TFunction; |
63 | class TVariable; |
64 | |
65 | // |
66 | // Base class for the tree nodes |
67 | // |
68 | class TIntermNode : angle::NonCopyable |
69 | { |
70 | public: |
71 | POOL_ALLOCATOR_NEW_DELETE |
72 | TIntermNode() |
73 | { |
74 | // TODO: Move this to TSourceLoc constructor |
75 | // after getting rid of TPublicType. |
76 | mLine.first_file = mLine.last_file = 0; |
77 | mLine.first_line = mLine.last_line = 0; |
78 | } |
79 | virtual ~TIntermNode() {} |
80 | |
81 | const TSourceLoc &getLine() const { return mLine; } |
82 | void setLine(const TSourceLoc &l) { mLine = l; } |
83 | |
84 | virtual void traverse(TIntermTraverser *it); |
85 | virtual bool visit(Visit visit, TIntermTraverser *it) = 0; |
86 | |
87 | virtual TIntermTyped *getAsTyped() { return nullptr; } |
88 | virtual TIntermConstantUnion *getAsConstantUnion() { return nullptr; } |
89 | virtual TIntermFunctionDefinition *getAsFunctionDefinition() { return nullptr; } |
90 | virtual TIntermAggregate *getAsAggregate() { return nullptr; } |
91 | virtual TIntermBlock *getAsBlock() { return nullptr; } |
92 | virtual TIntermFunctionPrototype *getAsFunctionPrototypeNode() { return nullptr; } |
93 | virtual TIntermInvariantDeclaration *getAsInvariantDeclarationNode() { return nullptr; } |
94 | virtual TIntermDeclaration *getAsDeclarationNode() { return nullptr; } |
95 | virtual TIntermSwizzle *getAsSwizzleNode() { return nullptr; } |
96 | virtual TIntermBinary *getAsBinaryNode() { return nullptr; } |
97 | virtual TIntermUnary *getAsUnaryNode() { return nullptr; } |
98 | virtual TIntermTernary *getAsTernaryNode() { return nullptr; } |
99 | virtual TIntermIfElse *getAsIfElseNode() { return nullptr; } |
100 | virtual TIntermSwitch *getAsSwitchNode() { return nullptr; } |
101 | virtual TIntermCase *getAsCaseNode() { return nullptr; } |
102 | virtual TIntermSymbol *getAsSymbolNode() { return nullptr; } |
103 | virtual TIntermLoop *getAsLoopNode() { return nullptr; } |
104 | virtual TIntermBranch *getAsBranchNode() { return nullptr; } |
105 | virtual TIntermPreprocessorDirective *getAsPreprocessorDirective() { return nullptr; } |
106 | |
107 | virtual size_t getChildCount() const = 0; |
108 | virtual TIntermNode *getChildNode(size_t index) const = 0; |
109 | // Replace a child node. Return true if |original| is a child |
110 | // node and it is replaced; otherwise, return false. |
111 | virtual bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) = 0; |
112 | |
113 | protected: |
114 | TSourceLoc mLine; |
115 | }; |
116 | |
117 | // |
118 | // This is just to help yacc. |
119 | // |
120 | struct TIntermNodePair |
121 | { |
122 | TIntermNode *node1; |
123 | TIntermNode *node2; |
124 | }; |
125 | |
126 | // |
127 | // Intermediate class for nodes that have a type. |
128 | // |
129 | class TIntermTyped : public TIntermNode |
130 | { |
131 | public: |
132 | TIntermTyped() {} |
133 | |
134 | virtual TIntermTyped *deepCopy() const = 0; |
135 | |
136 | TIntermTyped *getAsTyped() override { return this; } |
137 | |
138 | virtual TIntermTyped *fold(TDiagnostics *diagnostics) { return this; } |
139 | |
140 | // getConstantValue() returns the constant value that this node represents, if any. It |
141 | // should only be used after nodes have been replaced with their folded versions returned |
142 | // from fold(). hasConstantValue() returns true if getConstantValue() will return a value. |
143 | virtual bool hasConstantValue() const; |
144 | virtual const TConstantUnion *getConstantValue() const; |
145 | |
146 | // True if executing the expression represented by this node affects state, like values of |
147 | // variables. False if the executing the expression only computes its return value without |
148 | // affecting state. May return true conservatively. |
149 | virtual bool hasSideEffects() const = 0; |
150 | |
151 | virtual const TType &getType() const = 0; |
152 | |
153 | TBasicType getBasicType() const { return getType().getBasicType(); } |
154 | TQualifier getQualifier() const { return getType().getQualifier(); } |
155 | TPrecision getPrecision() const { return getType().getPrecision(); } |
156 | TMemoryQualifier getMemoryQualifier() const { return getType().getMemoryQualifier(); } |
157 | int getCols() const { return getType().getCols(); } |
158 | int getRows() const { return getType().getRows(); } |
159 | int getNominalSize() const { return getType().getNominalSize(); } |
160 | int getSecondarySize() const { return getType().getSecondarySize(); } |
161 | |
162 | bool isInterfaceBlock() const { return getType().isInterfaceBlock(); } |
163 | bool isMatrix() const { return getType().isMatrix(); } |
164 | bool isArray() const { return getType().isArray(); } |
165 | bool isVector() const { return getType().isVector(); } |
166 | bool isScalar() const { return getType().isScalar(); } |
167 | bool isScalarInt() const { return getType().isScalarInt(); } |
168 | const char *getBasicString() const { return getType().getBasicString(); } |
169 | |
170 | unsigned int getOutermostArraySize() const { return getType().getOutermostArraySize(); } |
171 | |
172 | protected: |
173 | TIntermTyped(const TIntermTyped &node); |
174 | }; |
175 | |
176 | // |
177 | // Handle for, do-while, and while loops. |
178 | // |
179 | enum TLoopType |
180 | { |
181 | ELoopFor, |
182 | ELoopWhile, |
183 | ELoopDoWhile |
184 | }; |
185 | |
186 | class TIntermLoop : public TIntermNode |
187 | { |
188 | public: |
189 | TIntermLoop(TLoopType type, |
190 | TIntermNode *init, |
191 | TIntermTyped *cond, |
192 | TIntermTyped *expr, |
193 | TIntermBlock *body); |
194 | |
195 | TIntermLoop *getAsLoopNode() override { return this; } |
196 | void traverse(TIntermTraverser *it) final; |
197 | bool visit(Visit visit, TIntermTraverser *it) final; |
198 | |
199 | size_t getChildCount() const final; |
200 | TIntermNode *getChildNode(size_t index) const final; |
201 | bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override; |
202 | |
203 | TLoopType getType() const { return mType; } |
204 | TIntermNode *getInit() { return mInit; } |
205 | TIntermTyped *getCondition() { return mCond; } |
206 | TIntermTyped *getExpression() { return mExpr; } |
207 | TIntermBlock *getBody() { return mBody; } |
208 | |
209 | void setInit(TIntermNode *init) { mInit = init; } |
210 | void setCondition(TIntermTyped *condition) { mCond = condition; } |
211 | void setExpression(TIntermTyped *expression) { mExpr = expression; } |
212 | void setBody(TIntermBlock *body) { mBody = body; } |
213 | |
214 | protected: |
215 | TLoopType mType; |
216 | TIntermNode *mInit; // for-loop initialization |
217 | TIntermTyped *mCond; // loop exit condition |
218 | TIntermTyped *mExpr; // for-loop expression |
219 | TIntermBlock *mBody; // loop body |
220 | }; |
221 | |
222 | // |
223 | // Handle break, continue, return, and kill. |
224 | // |
225 | class TIntermBranch : public TIntermNode |
226 | { |
227 | public: |
228 | TIntermBranch(TOperator op, TIntermTyped *e) : mFlowOp(op), mExpression(e) {} |
229 | |
230 | TIntermBranch *getAsBranchNode() override { return this; } |
231 | bool visit(Visit visit, TIntermTraverser *it) final; |
232 | |
233 | size_t getChildCount() const final; |
234 | TIntermNode *getChildNode(size_t index) const final; |
235 | bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override; |
236 | |
237 | TOperator getFlowOp() { return mFlowOp; } |
238 | TIntermTyped *getExpression() { return mExpression; } |
239 | |
240 | protected: |
241 | TOperator mFlowOp; |
242 | TIntermTyped *mExpression; // zero except for "return exp;" statements |
243 | }; |
244 | |
245 | // Nodes that correspond to variable symbols in the source code. These may be regular variables or |
246 | // interface block instances. In declarations that only declare a struct type but no variables, a |
247 | // TIntermSymbol node with an empty variable is used to store the type. |
248 | class TIntermSymbol : public TIntermTyped |
249 | { |
250 | public: |
251 | TIntermSymbol(const TVariable *variable); |
252 | |
253 | TIntermTyped *deepCopy() const override { return new TIntermSymbol(*this); } |
254 | |
255 | bool hasConstantValue() const override; |
256 | const TConstantUnion *getConstantValue() const override; |
257 | |
258 | bool hasSideEffects() const override { return false; } |
259 | |
260 | const TType &getType() const override; |
261 | |
262 | const TSymbolUniqueId &uniqueId() const; |
263 | ImmutableString getName() const; |
264 | const TVariable &variable() const { return *mVariable; } |
265 | |
266 | TIntermSymbol *getAsSymbolNode() override { return this; } |
267 | void traverse(TIntermTraverser *it) final; |
268 | bool visit(Visit visit, TIntermTraverser *it) final; |
269 | |
270 | size_t getChildCount() const final; |
271 | TIntermNode *getChildNode(size_t index) const final; |
272 | bool replaceChildNode(TIntermNode *, TIntermNode *) override { return false; } |
273 | |
274 | private: |
275 | TIntermSymbol(const TIntermSymbol &) = default; // Note: not deleted, just private! |
276 | |
277 | const TVariable *const mVariable; // Guaranteed to be non-null |
278 | }; |
279 | |
280 | // A typed expression that is not just representing a symbol table symbol. |
281 | class TIntermExpression : public TIntermTyped |
282 | { |
283 | public: |
284 | TIntermExpression(const TType &t); |
285 | |
286 | const TType &getType() const override { return mType; } |
287 | |
288 | protected: |
289 | TType *getTypePointer() { return &mType; } |
290 | void setType(const TType &t) { mType = t; } |
291 | void setTypePreservePrecision(const TType &t); |
292 | |
293 | TIntermExpression(const TIntermExpression &node) = default; |
294 | |
295 | TType mType; |
296 | }; |
297 | |
298 | // Constant folded node. |
299 | // Note that nodes may be constant folded and not be constant expressions with the EvqConst |
300 | // qualifier. This happens for example when the following expression is processed: |
301 | // "true ? 1.0 : non_constant" |
302 | // Other nodes than TIntermConstantUnion may also be constant expressions. |
303 | // |
304 | class TIntermConstantUnion : public TIntermExpression |
305 | { |
306 | public: |
307 | TIntermConstantUnion(const TConstantUnion *unionPointer, const TType &type) |
308 | : TIntermExpression(type), mUnionArrayPointer(unionPointer) |
309 | { |
310 | ASSERT(unionPointer); |
311 | } |
312 | |
313 | TIntermTyped *deepCopy() const override { return new TIntermConstantUnion(*this); } |
314 | |
315 | bool hasConstantValue() const override; |
316 | const TConstantUnion *getConstantValue() const override; |
317 | |
318 | bool hasSideEffects() const override { return false; } |
319 | |
320 | int getIConst(size_t index) const |
321 | { |
322 | return mUnionArrayPointer ? mUnionArrayPointer[index].getIConst() : 0; |
323 | } |
324 | unsigned int getUConst(size_t index) const |
325 | { |
326 | return mUnionArrayPointer ? mUnionArrayPointer[index].getUConst() : 0; |
327 | } |
328 | float getFConst(size_t index) const |
329 | { |
330 | return mUnionArrayPointer ? mUnionArrayPointer[index].getFConst() : 0.0f; |
331 | } |
332 | bool getBConst(size_t index) const |
333 | { |
334 | return mUnionArrayPointer ? mUnionArrayPointer[index].getBConst() : false; |
335 | } |
336 | |
337 | TIntermConstantUnion *getAsConstantUnion() override { return this; } |
338 | void traverse(TIntermTraverser *it) final; |
339 | bool visit(Visit visit, TIntermTraverser *it) final; |
340 | |
341 | size_t getChildCount() const final; |
342 | TIntermNode *getChildNode(size_t index) const final; |
343 | bool replaceChildNode(TIntermNode *, TIntermNode *) override { return false; } |
344 | |
345 | TConstantUnion *foldUnaryNonComponentWise(TOperator op); |
346 | TConstantUnion *foldUnaryComponentWise(TOperator op, TDiagnostics *diagnostics); |
347 | |
348 | static const TConstantUnion *FoldBinary(TOperator op, |
349 | const TConstantUnion *leftArray, |
350 | const TType &leftType, |
351 | const TConstantUnion *rightArray, |
352 | const TType &rightType, |
353 | TDiagnostics *diagnostics, |
354 | const TSourceLoc &line); |
355 | |
356 | static const TConstantUnion *FoldIndexing(const TType &type, |
357 | const TConstantUnion *constArray, |
358 | int index); |
359 | static TConstantUnion *FoldAggregateBuiltIn(TIntermAggregate *aggregate, |
360 | TDiagnostics *diagnostics); |
361 | |
362 | protected: |
363 | // Same data may be shared between multiple constant unions, so it can't be modified. |
364 | const TConstantUnion *mUnionArrayPointer; |
365 | |
366 | private: |
367 | typedef float (*FloatTypeUnaryFunc)(float); |
368 | void foldFloatTypeUnary(const TConstantUnion ¶meter, |
369 | FloatTypeUnaryFunc builtinFunc, |
370 | TConstantUnion *result) const; |
371 | |
372 | TIntermConstantUnion(const TIntermConstantUnion &node); // Note: not deleted, just private! |
373 | }; |
374 | |
375 | // |
376 | // Intermediate class for node types that hold operators. |
377 | // |
378 | class TIntermOperator : public TIntermExpression |
379 | { |
380 | public: |
381 | TOperator getOp() const { return mOp; } |
382 | |
383 | bool isAssignment() const; |
384 | bool isMultiplication() const; |
385 | bool isConstructor() const; |
386 | |
387 | // Returns true for calls mapped to EOpCall*, false for built-ins that have their own specific |
388 | // ops. |
389 | bool isFunctionCall() const; |
390 | |
391 | bool hasSideEffects() const override { return isAssignment(); } |
392 | |
393 | protected: |
394 | TIntermOperator(TOperator op) : TIntermExpression(TType(EbtFloat, EbpUndefined)), mOp(op) {} |
395 | TIntermOperator(TOperator op, const TType &type) : TIntermExpression(type), mOp(op) {} |
396 | |
397 | TIntermOperator(const TIntermOperator &) = default; |
398 | |
399 | const TOperator mOp; |
400 | }; |
401 | |
402 | // Node for vector swizzles. |
403 | class TIntermSwizzle : public TIntermExpression |
404 | { |
405 | public: |
406 | // This constructor determines the type of the node based on the operand. |
407 | TIntermSwizzle(TIntermTyped *operand, const TVector<int> &swizzleOffsets); |
408 | |
409 | TIntermTyped *deepCopy() const override { return new TIntermSwizzle(*this); } |
410 | |
411 | TIntermSwizzle *getAsSwizzleNode() override { return this; } |
412 | bool visit(Visit visit, TIntermTraverser *it) final; |
413 | |
414 | size_t getChildCount() const final; |
415 | TIntermNode *getChildNode(size_t index) const final; |
416 | bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override; |
417 | |
418 | bool hasSideEffects() const override { return mOperand->hasSideEffects(); } |
419 | |
420 | TIntermTyped *getOperand() { return mOperand; } |
421 | void writeOffsetsAsXYZW(TInfoSinkBase *out) const; |
422 | |
423 | const TVector<int> &getSwizzleOffsets() { return mSwizzleOffsets; } |
424 | |
425 | bool hasDuplicateOffsets() const; |
426 | void setHasFoldedDuplicateOffsets(bool hasFoldedDuplicateOffsets); |
427 | bool offsetsMatch(int offset) const; |
428 | |
429 | TIntermTyped *fold(TDiagnostics *diagnostics) override; |
430 | |
431 | protected: |
432 | TIntermTyped *mOperand; |
433 | TVector<int> mSwizzleOffsets; |
434 | bool mHasFoldedDuplicateOffsets; |
435 | |
436 | private: |
437 | void promote(); |
438 | |
439 | TIntermSwizzle(const TIntermSwizzle &node); // Note: not deleted, just private! |
440 | }; |
441 | |
442 | // |
443 | // Nodes for all the basic binary math operators. |
444 | // |
445 | class TIntermBinary : public TIntermOperator |
446 | { |
447 | public: |
448 | // This constructor determines the type of the binary node based on the operands and op. |
449 | TIntermBinary(TOperator op, TIntermTyped *left, TIntermTyped *right); |
450 | // Comma qualifier depends on the shader version, so use this to create comma nodes: |
451 | static TIntermBinary *CreateComma(TIntermTyped *left, TIntermTyped *right, int shaderVersion); |
452 | |
453 | TIntermTyped *deepCopy() const override { return new TIntermBinary(*this); } |
454 | |
455 | bool hasConstantValue() const override; |
456 | const TConstantUnion *getConstantValue() const override; |
457 | |
458 | static TOperator GetMulOpBasedOnOperands(const TType &left, const TType &right); |
459 | static TOperator GetMulAssignOpBasedOnOperands(const TType &left, const TType &right); |
460 | |
461 | TIntermBinary *getAsBinaryNode() override { return this; } |
462 | void traverse(TIntermTraverser *it) final; |
463 | bool visit(Visit visit, TIntermTraverser *it) final; |
464 | |
465 | size_t getChildCount() const final; |
466 | TIntermNode *getChildNode(size_t index) const final; |
467 | bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override; |
468 | |
469 | bool hasSideEffects() const override |
470 | { |
471 | return isAssignment() || mLeft->hasSideEffects() || mRight->hasSideEffects(); |
472 | } |
473 | |
474 | TIntermTyped *getLeft() const { return mLeft; } |
475 | TIntermTyped *getRight() const { return mRight; } |
476 | TIntermTyped *fold(TDiagnostics *diagnostics) override; |
477 | |
478 | void setAddIndexClamp() { mAddIndexClamp = true; } |
479 | bool getAddIndexClamp() const { return mAddIndexClamp; } |
480 | |
481 | // This method is only valid for EOpIndexDirectStruct. It returns the name of the field. |
482 | const ImmutableString &getIndexStructFieldName() const; |
483 | |
484 | protected: |
485 | TIntermTyped *mLeft; |
486 | TIntermTyped *mRight; |
487 | |
488 | // If set to true, wrap any EOpIndexIndirect with a clamp to bounds. |
489 | bool mAddIndexClamp; |
490 | |
491 | private: |
492 | void promote(); |
493 | |
494 | static TQualifier GetCommaQualifier(int shaderVersion, |
495 | const TIntermTyped *left, |
496 | const TIntermTyped *right); |
497 | |
498 | TIntermBinary(const TIntermBinary &node); // Note: not deleted, just private! |
499 | }; |
500 | |
501 | // |
502 | // Nodes for unary math operators. |
503 | // |
504 | class TIntermUnary : public TIntermOperator |
505 | { |
506 | public: |
507 | TIntermUnary(TOperator op, TIntermTyped *operand, const TFunction *function); |
508 | |
509 | TIntermTyped *deepCopy() const override { return new TIntermUnary(*this); } |
510 | |
511 | TIntermUnary *getAsUnaryNode() override { return this; } |
512 | void traverse(TIntermTraverser *it) final; |
513 | bool visit(Visit visit, TIntermTraverser *it) final; |
514 | |
515 | size_t getChildCount() const final; |
516 | TIntermNode *getChildNode(size_t index) const final; |
517 | bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override; |
518 | |
519 | bool hasSideEffects() const override { return isAssignment() || mOperand->hasSideEffects(); } |
520 | |
521 | TIntermTyped *getOperand() { return mOperand; } |
522 | TIntermTyped *fold(TDiagnostics *diagnostics) override; |
523 | |
524 | const TFunction *getFunction() const { return mFunction; } |
525 | |
526 | void setUseEmulatedFunction() { mUseEmulatedFunction = true; } |
527 | bool getUseEmulatedFunction() { return mUseEmulatedFunction; } |
528 | |
529 | protected: |
530 | TIntermTyped *mOperand; |
531 | |
532 | // If set to true, replace the built-in function call with an emulated one |
533 | // to work around driver bugs. |
534 | bool mUseEmulatedFunction; |
535 | |
536 | const TFunction *const mFunction; |
537 | |
538 | private: |
539 | void promote(); |
540 | |
541 | TIntermUnary(const TIntermUnary &node); // note: not deleted, just private! |
542 | }; |
543 | |
544 | typedef TVector<TIntermNode *> TIntermSequence; |
545 | typedef TVector<int> TQualifierList; |
546 | |
547 | // Interface for node classes that have an arbitrarily sized set of children. |
548 | class TIntermAggregateBase |
549 | { |
550 | public: |
551 | virtual ~TIntermAggregateBase() {} |
552 | |
553 | virtual TIntermSequence *getSequence() = 0; |
554 | virtual const TIntermSequence *getSequence() const = 0; |
555 | |
556 | bool replaceChildNodeWithMultiple(TIntermNode *original, const TIntermSequence &replacements); |
557 | bool insertChildNodes(TIntermSequence::size_type position, const TIntermSequence &insertions); |
558 | |
559 | protected: |
560 | TIntermAggregateBase() {} |
561 | |
562 | bool replaceChildNodeInternal(TIntermNode *original, TIntermNode *replacement); |
563 | }; |
564 | |
565 | // |
566 | // Nodes that operate on an arbitrary sized set of children. |
567 | // |
568 | class TIntermAggregate : public TIntermOperator, public TIntermAggregateBase |
569 | { |
570 | public: |
571 | static TIntermAggregate *CreateFunctionCall(const TFunction &func, TIntermSequence *arguments); |
572 | |
573 | static TIntermAggregate *CreateRawFunctionCall(const TFunction &func, |
574 | TIntermSequence *arguments); |
575 | |
576 | // This covers all built-in function calls - whether they are associated with an op or not. |
577 | static TIntermAggregate *CreateBuiltInFunctionCall(const TFunction &func, |
578 | TIntermSequence *arguments); |
579 | static TIntermAggregate *CreateConstructor(const TType &type, TIntermSequence *arguments); |
580 | ~TIntermAggregate() {} |
581 | |
582 | // Note: only supported for nodes that can be a part of an expression. |
583 | TIntermTyped *deepCopy() const override { return new TIntermAggregate(*this); } |
584 | |
585 | TIntermAggregate *shallowCopy() const; |
586 | |
587 | bool hasConstantValue() const override; |
588 | const TConstantUnion *getConstantValue() const override; |
589 | |
590 | TIntermAggregate *getAsAggregate() override { return this; } |
591 | void traverse(TIntermTraverser *it) final; |
592 | bool visit(Visit visit, TIntermTraverser *it) final; |
593 | |
594 | size_t getChildCount() const final; |
595 | TIntermNode *getChildNode(size_t index) const final; |
596 | bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override; |
597 | |
598 | bool hasSideEffects() const override; |
599 | |
600 | TIntermTyped *fold(TDiagnostics *diagnostics) override; |
601 | |
602 | TIntermSequence *getSequence() override { return &mArguments; } |
603 | const TIntermSequence *getSequence() const override { return &mArguments; } |
604 | |
605 | void setUseEmulatedFunction() { mUseEmulatedFunction = true; } |
606 | bool getUseEmulatedFunction() { return mUseEmulatedFunction; } |
607 | |
608 | // Returns true if changing parameter precision may affect the return value. |
609 | bool gotPrecisionFromChildren() const { return mGotPrecisionFromChildren; } |
610 | |
611 | const TFunction *getFunction() const { return mFunction; } |
612 | |
613 | // Get the function name to display to the user in an error message. |
614 | const char *functionName() const; |
615 | |
616 | protected: |
617 | TIntermSequence mArguments; |
618 | |
619 | // If set to true, replace the built-in function call with an emulated one |
620 | // to work around driver bugs. Only for calls mapped to ops other than EOpCall*. |
621 | bool mUseEmulatedFunction; |
622 | |
623 | bool mGotPrecisionFromChildren; |
624 | |
625 | const TFunction *const mFunction; |
626 | |
627 | private: |
628 | TIntermAggregate(const TFunction *func, |
629 | const TType &type, |
630 | TOperator op, |
631 | TIntermSequence *arguments); |
632 | |
633 | TIntermAggregate(const TIntermAggregate &node); // note: not deleted, just private! |
634 | |
635 | void setPrecisionAndQualifier(); |
636 | |
637 | bool areChildrenConstQualified(); |
638 | |
639 | void setPrecisionFromChildren(); |
640 | |
641 | void setPrecisionForBuiltInOp(); |
642 | |
643 | // Returns true if precision was set according to special rules for this built-in. |
644 | bool setPrecisionForSpecialBuiltInOp(); |
645 | |
646 | // Used for built-in functions under EOpCallBuiltInFunction. The function name in the symbol |
647 | // info needs to be set before calling this. |
648 | void setBuiltInFunctionPrecision(); |
649 | }; |
650 | |
651 | // A list of statements. Either the root node which contains declarations and function definitions, |
652 | // or a block that can be marked with curly braces {}. |
653 | class TIntermBlock : public TIntermNode, public TIntermAggregateBase |
654 | { |
655 | public: |
656 | TIntermBlock() : TIntermNode() {} |
657 | ~TIntermBlock() {} |
658 | |
659 | TIntermBlock *getAsBlock() override { return this; } |
660 | void traverse(TIntermTraverser *it) final; |
661 | bool visit(Visit visit, TIntermTraverser *it) final; |
662 | |
663 | size_t getChildCount() const final; |
664 | TIntermNode *getChildNode(size_t index) const final; |
665 | bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override; |
666 | |
667 | // Only intended for initially building the block. |
668 | void appendStatement(TIntermNode *statement); |
669 | void insertStatement(size_t insertPosition, TIntermNode *statement); |
670 | |
671 | TIntermSequence *getSequence() override { return &mStatements; } |
672 | const TIntermSequence *getSequence() const override { return &mStatements; } |
673 | |
674 | protected: |
675 | TIntermSequence mStatements; |
676 | }; |
677 | |
678 | // Function prototype. May be in the AST either as a function prototype declaration or as a part of |
679 | // a function definition. The type of the node is the function return type. |
680 | class TIntermFunctionPrototype : public TIntermTyped |
681 | { |
682 | public: |
683 | TIntermFunctionPrototype(const TFunction *function); |
684 | ~TIntermFunctionPrototype() {} |
685 | |
686 | TIntermFunctionPrototype *getAsFunctionPrototypeNode() override { return this; } |
687 | void traverse(TIntermTraverser *it) final; |
688 | bool visit(Visit visit, TIntermTraverser *it) final; |
689 | |
690 | size_t getChildCount() const final; |
691 | TIntermNode *getChildNode(size_t index) const final; |
692 | bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override; |
693 | |
694 | const TType &getType() const override; |
695 | |
696 | TIntermTyped *deepCopy() const override |
697 | { |
698 | UNREACHABLE(); |
699 | return nullptr; |
700 | } |
701 | bool hasSideEffects() const override |
702 | { |
703 | UNREACHABLE(); |
704 | return true; |
705 | } |
706 | |
707 | const TFunction *getFunction() const { return mFunction; } |
708 | |
709 | protected: |
710 | const TFunction *const mFunction; |
711 | }; |
712 | |
713 | // Node for function definitions. The prototype child node stores the function header including |
714 | // parameters, and the body child node stores the function body. |
715 | class TIntermFunctionDefinition : public TIntermNode |
716 | { |
717 | public: |
718 | TIntermFunctionDefinition(TIntermFunctionPrototype *prototype, TIntermBlock *body) |
719 | : TIntermNode(), mPrototype(prototype), mBody(body) |
720 | { |
721 | ASSERT(prototype != nullptr); |
722 | ASSERT(body != nullptr); |
723 | } |
724 | |
725 | TIntermFunctionDefinition *getAsFunctionDefinition() override { return this; } |
726 | void traverse(TIntermTraverser *it) final; |
727 | bool visit(Visit visit, TIntermTraverser *it) final; |
728 | |
729 | size_t getChildCount() const final; |
730 | TIntermNode *getChildNode(size_t index) const final; |
731 | bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override; |
732 | |
733 | TIntermFunctionPrototype *getFunctionPrototype() const { return mPrototype; } |
734 | TIntermBlock *getBody() const { return mBody; } |
735 | |
736 | const TFunction *getFunction() const { return mPrototype->getFunction(); } |
737 | |
738 | private: |
739 | TIntermFunctionPrototype *mPrototype; |
740 | TIntermBlock *mBody; |
741 | }; |
742 | |
743 | // Struct, interface block or variable declaration. Can contain multiple variable declarators. |
744 | class TIntermDeclaration : public TIntermNode, public TIntermAggregateBase |
745 | { |
746 | public: |
747 | TIntermDeclaration() : TIntermNode() {} |
748 | ~TIntermDeclaration() {} |
749 | |
750 | TIntermDeclaration *getAsDeclarationNode() override { return this; } |
751 | bool visit(Visit visit, TIntermTraverser *it) final; |
752 | |
753 | size_t getChildCount() const final; |
754 | TIntermNode *getChildNode(size_t index) const final; |
755 | bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override; |
756 | |
757 | // Only intended for initially building the declaration. |
758 | // The declarator node should be either TIntermSymbol or TIntermBinary with op set to |
759 | // EOpInitialize. |
760 | void appendDeclarator(TIntermTyped *declarator); |
761 | |
762 | TIntermSequence *getSequence() override { return &mDeclarators; } |
763 | const TIntermSequence *getSequence() const override { return &mDeclarators; } |
764 | |
765 | protected: |
766 | TIntermSequence mDeclarators; |
767 | }; |
768 | |
769 | // Specialized declarations for attributing invariance. |
770 | class TIntermInvariantDeclaration : public TIntermNode |
771 | { |
772 | public: |
773 | TIntermInvariantDeclaration(TIntermSymbol *symbol, const TSourceLoc &line); |
774 | |
775 | virtual TIntermInvariantDeclaration *getAsInvariantDeclarationNode() override { return this; } |
776 | bool visit(Visit visit, TIntermTraverser *it) final; |
777 | |
778 | TIntermSymbol *getSymbol() { return mSymbol; } |
779 | |
780 | size_t getChildCount() const final; |
781 | TIntermNode *getChildNode(size_t index) const final; |
782 | bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override; |
783 | |
784 | private: |
785 | TIntermSymbol *mSymbol; |
786 | }; |
787 | |
788 | // For ternary operators like a ? b : c. |
789 | class TIntermTernary : public TIntermExpression |
790 | { |
791 | public: |
792 | TIntermTernary(TIntermTyped *cond, TIntermTyped *trueExpression, TIntermTyped *falseExpression); |
793 | |
794 | TIntermTernary *getAsTernaryNode() override { return this; } |
795 | bool visit(Visit visit, TIntermTraverser *it) final; |
796 | |
797 | size_t getChildCount() const final; |
798 | TIntermNode *getChildNode(size_t index) const final; |
799 | bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override; |
800 | |
801 | TIntermTyped *getCondition() const { return mCondition; } |
802 | TIntermTyped *getTrueExpression() const { return mTrueExpression; } |
803 | TIntermTyped *getFalseExpression() const { return mFalseExpression; } |
804 | |
805 | TIntermTyped *deepCopy() const override { return new TIntermTernary(*this); } |
806 | |
807 | bool hasSideEffects() const override |
808 | { |
809 | return mCondition->hasSideEffects() || mTrueExpression->hasSideEffects() || |
810 | mFalseExpression->hasSideEffects(); |
811 | } |
812 | |
813 | TIntermTyped *fold(TDiagnostics *diagnostics) override; |
814 | |
815 | private: |
816 | TIntermTernary(const TIntermTernary &node); // Note: not deleted, just private! |
817 | |
818 | static TQualifier DetermineQualifier(TIntermTyped *cond, |
819 | TIntermTyped *trueExpression, |
820 | TIntermTyped *falseExpression); |
821 | |
822 | TIntermTyped *mCondition; |
823 | TIntermTyped *mTrueExpression; |
824 | TIntermTyped *mFalseExpression; |
825 | }; |
826 | |
827 | class TIntermIfElse : public TIntermNode |
828 | { |
829 | public: |
830 | TIntermIfElse(TIntermTyped *cond, TIntermBlock *trueB, TIntermBlock *falseB); |
831 | |
832 | TIntermIfElse *getAsIfElseNode() override { return this; } |
833 | bool visit(Visit visit, TIntermTraverser *it) final; |
834 | |
835 | size_t getChildCount() const final; |
836 | TIntermNode *getChildNode(size_t index) const final; |
837 | bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override; |
838 | |
839 | TIntermTyped *getCondition() const { return mCondition; } |
840 | TIntermBlock *getTrueBlock() const { return mTrueBlock; } |
841 | TIntermBlock *getFalseBlock() const { return mFalseBlock; } |
842 | |
843 | protected: |
844 | TIntermTyped *mCondition; |
845 | TIntermBlock *mTrueBlock; |
846 | TIntermBlock *mFalseBlock; |
847 | }; |
848 | |
849 | // |
850 | // Switch statement. |
851 | // |
852 | class TIntermSwitch : public TIntermNode |
853 | { |
854 | public: |
855 | TIntermSwitch(TIntermTyped *init, TIntermBlock *statementList); |
856 | |
857 | TIntermSwitch *getAsSwitchNode() override { return this; } |
858 | bool visit(Visit visit, TIntermTraverser *it) final; |
859 | |
860 | size_t getChildCount() const final; |
861 | TIntermNode *getChildNode(size_t index) const final; |
862 | bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override; |
863 | |
864 | TIntermTyped *getInit() { return mInit; } |
865 | TIntermBlock *getStatementList() { return mStatementList; } |
866 | |
867 | // Must be called with a non-null statementList. |
868 | void setStatementList(TIntermBlock *statementList); |
869 | |
870 | protected: |
871 | TIntermTyped *mInit; |
872 | TIntermBlock *mStatementList; |
873 | }; |
874 | |
875 | // |
876 | // Case label. |
877 | // |
878 | class TIntermCase : public TIntermNode |
879 | { |
880 | public: |
881 | TIntermCase(TIntermTyped *condition) : TIntermNode(), mCondition(condition) {} |
882 | |
883 | TIntermCase *getAsCaseNode() override { return this; } |
884 | bool visit(Visit visit, TIntermTraverser *it) final; |
885 | |
886 | size_t getChildCount() const final; |
887 | TIntermNode *getChildNode(size_t index) const final; |
888 | bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override; |
889 | |
890 | bool hasCondition() const { return mCondition != nullptr; } |
891 | TIntermTyped *getCondition() const { return mCondition; } |
892 | |
893 | protected: |
894 | TIntermTyped *mCondition; |
895 | }; |
896 | |
897 | // |
898 | // Preprocessor Directive. |
899 | // #ifdef, #define, #if, #endif, etc. |
900 | // |
901 | |
902 | enum class PreprocessorDirective |
903 | { |
904 | Define, |
905 | Ifdef, |
906 | If, |
907 | Endif, |
908 | }; |
909 | |
910 | class TIntermPreprocessorDirective : public TIntermNode |
911 | { |
912 | public: |
913 | // This could also take an ImmutbleString as an argument. |
914 | TIntermPreprocessorDirective(PreprocessorDirective directive, ImmutableString command); |
915 | ~TIntermPreprocessorDirective() final; |
916 | |
917 | void traverse(TIntermTraverser *it) final; |
918 | bool visit(Visit visit, TIntermTraverser *it) final; |
919 | bool replaceChildNode(TIntermNode *, TIntermNode *) final { return false; } |
920 | |
921 | TIntermPreprocessorDirective *getAsPreprocessorDirective() final { return this; } |
922 | size_t getChildCount() const final; |
923 | TIntermNode *getChildNode(size_t index) const final; |
924 | |
925 | PreprocessorDirective getDirective() const { return mDirective; } |
926 | const ImmutableString &getCommand() const { return mCommand; } |
927 | |
928 | private: |
929 | PreprocessorDirective mDirective; |
930 | ImmutableString mCommand; |
931 | }; |
932 | |
933 | } // namespace sh |
934 | |
935 | #endif // COMPILER_TRANSLATOR_INTERMNODE_H_ |
936 | |