Line data Source code
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/Operator.h"
28 : #include "compiler/translator/Types.h"
29 :
30 : namespace sh
31 : {
32 :
33 : class TDiagnostics;
34 :
35 : class TIntermTraverser;
36 : class TIntermAggregate;
37 : class TIntermBlock;
38 : class TIntermDeclaration;
39 : class TIntermFunctionDefinition;
40 : class TIntermSwizzle;
41 : class TIntermBinary;
42 : class TIntermUnary;
43 : class TIntermConstantUnion;
44 : class TIntermTernary;
45 : class TIntermIfElse;
46 : class TIntermSwitch;
47 : class TIntermCase;
48 : class TIntermTyped;
49 : class TIntermSymbol;
50 : class TIntermLoop;
51 : class TInfoSink;
52 : class TInfoSinkBase;
53 : class TIntermRaw;
54 : class TIntermBranch;
55 :
56 : class TSymbolTable;
57 : class TFunction;
58 :
59 : // Encapsulate an identifier string and track whether it is coming from the original shader code
60 : // (not internal) or from ANGLE (internal). Usually internal names shouldn't be decorated or hashed.
61 0 : class TName
62 : {
63 : public:
64 : POOL_ALLOCATOR_NEW_DELETE();
65 0 : explicit TName(const TString &name) : mName(name), mIsInternal(false) {}
66 0 : TName() : mName(), mIsInternal(false) {}
67 0 : TName(const TName &) = default;
68 : TName &operator=(const TName &) = default;
69 :
70 0 : const TString &getString() const { return mName; }
71 0 : void setString(const TString &string) { mName = string; }
72 0 : bool isInternal() const { return mIsInternal; }
73 0 : void setInternal(bool isInternal) { mIsInternal = isInternal; }
74 :
75 : private:
76 : TString mName;
77 : bool mIsInternal;
78 : };
79 :
80 : //
81 : // Base class for the tree nodes
82 : //
83 : class TIntermNode : angle::NonCopyable
84 : {
85 : public:
86 0 : POOL_ALLOCATOR_NEW_DELETE();
87 0 : TIntermNode()
88 0 : {
89 : // TODO: Move this to TSourceLoc constructor
90 : // after getting rid of TPublicType.
91 0 : mLine.first_file = mLine.last_file = 0;
92 0 : mLine.first_line = mLine.last_line = 0;
93 0 : }
94 0 : virtual ~TIntermNode() { }
95 :
96 0 : const TSourceLoc &getLine() const { return mLine; }
97 0 : void setLine(const TSourceLoc &l) { mLine = l; }
98 :
99 : virtual void traverse(TIntermTraverser *) = 0;
100 0 : virtual TIntermTyped *getAsTyped() { return 0; }
101 0 : virtual TIntermConstantUnion *getAsConstantUnion() { return 0; }
102 0 : virtual TIntermFunctionDefinition *getAsFunctionDefinition() { return nullptr; }
103 0 : virtual TIntermAggregate *getAsAggregate() { return 0; }
104 0 : virtual TIntermBlock *getAsBlock() { return nullptr; }
105 0 : virtual TIntermDeclaration *getAsDeclarationNode() { return nullptr; }
106 0 : virtual TIntermSwizzle *getAsSwizzleNode() { return nullptr; }
107 0 : virtual TIntermBinary *getAsBinaryNode() { return 0; }
108 0 : virtual TIntermUnary *getAsUnaryNode() { return 0; }
109 0 : virtual TIntermTernary *getAsTernaryNode() { return nullptr; }
110 0 : virtual TIntermIfElse *getAsIfElseNode() { return nullptr; }
111 0 : virtual TIntermSwitch *getAsSwitchNode() { return 0; }
112 0 : virtual TIntermCase *getAsCaseNode() { return 0; }
113 0 : virtual TIntermSymbol *getAsSymbolNode() { return 0; }
114 0 : virtual TIntermLoop *getAsLoopNode() { return 0; }
115 0 : virtual TIntermRaw *getAsRawNode() { return 0; }
116 0 : virtual TIntermBranch *getAsBranchNode() { return 0; }
117 :
118 : // Replace a child node. Return true if |original| is a child
119 : // node and it is replaced; otherwise, return false.
120 : virtual bool replaceChildNode(
121 : TIntermNode *original, TIntermNode *replacement) = 0;
122 :
123 : protected:
124 : TSourceLoc mLine;
125 : };
126 :
127 : //
128 : // This is just to help yacc.
129 : //
130 : struct TIntermNodePair
131 : {
132 : TIntermNode *node1;
133 : TIntermNode *node2;
134 : };
135 :
136 : //
137 : // Intermediate class for nodes that have a type.
138 : //
139 0 : class TIntermTyped : public TIntermNode
140 : {
141 : public:
142 0 : TIntermTyped(const TType &t) : mType(t) { }
143 :
144 : virtual TIntermTyped *deepCopy() const = 0;
145 :
146 0 : TIntermTyped *getAsTyped() override { return this; }
147 :
148 : virtual bool hasSideEffects() const = 0;
149 :
150 0 : void setType(const TType &t) { mType = t; }
151 : void setTypePreservePrecision(const TType &t);
152 0 : const TType &getType() const { return mType; }
153 0 : TType *getTypePointer() { return &mType; }
154 :
155 0 : TBasicType getBasicType() const { return mType.getBasicType(); }
156 0 : TQualifier getQualifier() const { return mType.getQualifier(); }
157 0 : TPrecision getPrecision() const { return mType.getPrecision(); }
158 0 : TMemoryQualifier getMemoryQualifier() const { return mType.getMemoryQualifier(); }
159 0 : int getCols() const { return mType.getCols(); }
160 0 : int getRows() const { return mType.getRows(); }
161 0 : int getNominalSize() const { return mType.getNominalSize(); }
162 0 : int getSecondarySize() const { return mType.getSecondarySize(); }
163 :
164 0 : bool isInterfaceBlock() const { return mType.isInterfaceBlock(); }
165 0 : bool isMatrix() const { return mType.isMatrix(); }
166 0 : bool isArray() const { return mType.isArray(); }
167 0 : bool isVector() const { return mType.isVector(); }
168 0 : bool isScalar() const { return mType.isScalar(); }
169 0 : bool isScalarInt() const { return mType.isScalarInt(); }
170 : const char *getBasicString() const { return mType.getBasicString(); }
171 0 : TString getCompleteString() const { return mType.getCompleteString(); }
172 :
173 0 : unsigned int getArraySize() const { return mType.getArraySize(); }
174 :
175 : bool isConstructorWithOnlyConstantUnionParameters();
176 :
177 : static TIntermTyped *CreateIndexNode(int index);
178 : static TIntermTyped *CreateZero(const TType &type);
179 :
180 : protected:
181 : TType mType;
182 :
183 : TIntermTyped(const TIntermTyped &node);
184 : };
185 :
186 : //
187 : // Handle for, do-while, and while loops.
188 : //
189 : enum TLoopType
190 : {
191 : ELoopFor,
192 : ELoopWhile,
193 : ELoopDoWhile
194 : };
195 :
196 0 : class TIntermLoop : public TIntermNode
197 : {
198 : public:
199 0 : TIntermLoop(TLoopType type,
200 : TIntermNode *init,
201 : TIntermTyped *cond,
202 : TIntermTyped *expr,
203 : TIntermBlock *body)
204 0 : : mType(type), mInit(init), mCond(cond), mExpr(expr), mBody(body)
205 : {
206 0 : }
207 :
208 0 : TIntermLoop *getAsLoopNode() override { return this; }
209 : void traverse(TIntermTraverser *it) override;
210 : bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override;
211 :
212 0 : TLoopType getType() const { return mType; }
213 0 : TIntermNode *getInit() { return mInit; }
214 0 : TIntermTyped *getCondition() { return mCond; }
215 0 : TIntermTyped *getExpression() { return mExpr; }
216 0 : TIntermBlock *getBody() { return mBody; }
217 :
218 0 : void setCondition(TIntermTyped *condition) { mCond = condition; }
219 : void setExpression(TIntermTyped *expression) { mExpr = expression; }
220 0 : void setBody(TIntermBlock *body) { mBody = body; }
221 :
222 : protected:
223 : TLoopType mType;
224 : TIntermNode *mInit; // for-loop initialization
225 : TIntermTyped *mCond; // loop exit condition
226 : TIntermTyped *mExpr; // for-loop expression
227 : TIntermBlock *mBody; // loop body
228 : };
229 :
230 : //
231 : // Handle break, continue, return, and kill.
232 : //
233 0 : class TIntermBranch : public TIntermNode
234 : {
235 : public:
236 0 : TIntermBranch(TOperator op, TIntermTyped *e)
237 0 : : mFlowOp(op),
238 0 : mExpression(e) { }
239 :
240 : void traverse(TIntermTraverser *it) override;
241 0 : TIntermBranch *getAsBranchNode() override { return this; }
242 : bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override;
243 :
244 0 : TOperator getFlowOp() { return mFlowOp; }
245 0 : TIntermTyped* getExpression() { return mExpression; }
246 :
247 : protected:
248 : TOperator mFlowOp;
249 : TIntermTyped *mExpression; // non-zero except for "return exp;" statements
250 : };
251 :
252 : //
253 : // Nodes that correspond to symbols or constants in the source code.
254 : //
255 0 : class TIntermSymbol : public TIntermTyped
256 : {
257 : public:
258 : // if symbol is initialized as symbol(sym), the memory comes from the poolallocator of sym.
259 : // If sym comes from per process globalpoolallocator, then it causes increased memory usage
260 : // per compile it is essential to use "symbol = sym" to assign to symbol
261 0 : TIntermSymbol(int id, const TString &symbol, const TType &type)
262 0 : : TIntermTyped(type), mId(id), mSymbol(symbol)
263 : {
264 0 : }
265 :
266 0 : TIntermTyped *deepCopy() const override { return new TIntermSymbol(*this); }
267 :
268 0 : bool hasSideEffects() const override { return false; }
269 :
270 0 : int getId() const { return mId; }
271 0 : const TString &getSymbol() const { return mSymbol.getString(); }
272 0 : const TName &getName() const { return mSymbol; }
273 :
274 0 : void setId(int newId) { mId = newId; }
275 :
276 0 : void setInternal(bool internal) { mSymbol.setInternal(internal); }
277 :
278 : void traverse(TIntermTraverser *it) override;
279 0 : TIntermSymbol *getAsSymbolNode() override { return this; }
280 0 : bool replaceChildNode(TIntermNode *, TIntermNode *) override { return false; }
281 :
282 : protected:
283 : int mId;
284 : TName mSymbol;
285 :
286 : private:
287 0 : TIntermSymbol(const TIntermSymbol &) = default; // Note: not deleted, just private!
288 : };
289 :
290 : // A Raw node stores raw code, that the translator will insert verbatim
291 : // into the output stream. Useful for transformation operations that make
292 : // complex code that might not fit naturally into the GLSL model.
293 0 : class TIntermRaw : public TIntermTyped
294 : {
295 : public:
296 0 : TIntermRaw(const TType &type, const TString &rawText)
297 0 : : TIntermTyped(type),
298 0 : mRawText(rawText) { }
299 : TIntermRaw(const TIntermRaw &) = delete;
300 :
301 0 : TIntermTyped *deepCopy() const override
302 : {
303 0 : UNREACHABLE();
304 : return nullptr;
305 : }
306 :
307 0 : bool hasSideEffects() const override { return false; }
308 :
309 0 : TString getRawText() const { return mRawText; }
310 :
311 : void traverse(TIntermTraverser *it) override;
312 :
313 0 : TIntermRaw *getAsRawNode() override { return this; }
314 0 : bool replaceChildNode(TIntermNode *, TIntermNode *) override { return false; }
315 :
316 : protected:
317 : TString mRawText;
318 : };
319 :
320 : // Constant folded node.
321 : // Note that nodes may be constant folded and not be constant expressions with the EvqConst
322 : // qualifier. This happens for example when the following expression is processed:
323 : // "true ? 1.0 : non_constant"
324 : // Other nodes than TIntermConstantUnion may also be constant expressions.
325 : //
326 0 : class TIntermConstantUnion : public TIntermTyped
327 : {
328 : public:
329 0 : TIntermConstantUnion(const TConstantUnion *unionPointer, const TType &type)
330 0 : : TIntermTyped(type), mUnionArrayPointer(unionPointer)
331 : {
332 0 : ASSERT(unionPointer);
333 0 : }
334 :
335 0 : TIntermTyped *deepCopy() const override { return new TIntermConstantUnion(*this); }
336 :
337 0 : bool hasSideEffects() const override { return false; }
338 :
339 0 : const TConstantUnion *getUnionArrayPointer() const { return mUnionArrayPointer; }
340 :
341 0 : int getIConst(size_t index) const
342 : {
343 0 : return mUnionArrayPointer ? mUnionArrayPointer[index].getIConst() : 0;
344 : }
345 0 : unsigned int getUConst(size_t index) const
346 : {
347 0 : return mUnionArrayPointer ? mUnionArrayPointer[index].getUConst() : 0;
348 : }
349 : float getFConst(size_t index) const
350 : {
351 : return mUnionArrayPointer ? mUnionArrayPointer[index].getFConst() : 0.0f;
352 : }
353 0 : bool getBConst(size_t index) const
354 : {
355 0 : return mUnionArrayPointer ? mUnionArrayPointer[index].getBConst() : false;
356 : }
357 :
358 0 : void replaceConstantUnion(const TConstantUnion *safeConstantUnion)
359 : {
360 0 : ASSERT(safeConstantUnion);
361 : // Previous union pointer freed on pool deallocation.
362 0 : mUnionArrayPointer = safeConstantUnion;
363 0 : }
364 :
365 0 : TIntermConstantUnion *getAsConstantUnion() override { return this; }
366 : void traverse(TIntermTraverser *it) override;
367 0 : bool replaceChildNode(TIntermNode *, TIntermNode *) override { return false; }
368 :
369 : TConstantUnion *foldBinary(TOperator op,
370 : TIntermConstantUnion *rightNode,
371 : TDiagnostics *diagnostics,
372 : const TSourceLoc &line);
373 : const TConstantUnion *foldIndexing(int index);
374 : TConstantUnion *foldUnaryNonComponentWise(TOperator op);
375 : TConstantUnion *foldUnaryComponentWise(TOperator op, TDiagnostics *diagnostics);
376 :
377 : static TConstantUnion *FoldAggregateConstructor(TIntermAggregate *aggregate);
378 : static TConstantUnion *FoldAggregateBuiltIn(TIntermAggregate *aggregate,
379 : TDiagnostics *diagnostics);
380 :
381 : protected:
382 : // Same data may be shared between multiple constant unions, so it can't be modified.
383 : const TConstantUnion *mUnionArrayPointer;
384 :
385 : private:
386 : typedef float(*FloatTypeUnaryFunc) (float);
387 : void foldFloatTypeUnary(const TConstantUnion ¶meter,
388 : FloatTypeUnaryFunc builtinFunc,
389 : TConstantUnion *result) const;
390 :
391 : TIntermConstantUnion(const TIntermConstantUnion &node); // Note: not deleted, just private!
392 : };
393 :
394 : //
395 : // Intermediate class for node types that hold operators.
396 : //
397 0 : class TIntermOperator : public TIntermTyped
398 : {
399 : public:
400 0 : TOperator getOp() const { return mOp; }
401 :
402 : bool isAssignment() const;
403 : bool isMultiplication() const;
404 : bool isConstructor() const;
405 :
406 0 : bool hasSideEffects() const override { return isAssignment(); }
407 :
408 : protected:
409 0 : TIntermOperator(TOperator op)
410 0 : : TIntermTyped(TType(EbtFloat, EbpUndefined)),
411 0 : mOp(op) {}
412 : TIntermOperator(TOperator op, const TType &type)
413 : : TIntermTyped(type),
414 : mOp(op) {}
415 :
416 0 : TIntermOperator(const TIntermOperator &) = default;
417 :
418 : TOperator mOp;
419 : };
420 :
421 : // Node for vector swizzles.
422 0 : class TIntermSwizzle : public TIntermTyped
423 : {
424 : public:
425 : // This constructor determines the type of the node based on the operand.
426 : TIntermSwizzle(TIntermTyped *operand, const TVector<int> &swizzleOffsets);
427 :
428 0 : TIntermTyped *deepCopy() const override { return new TIntermSwizzle(*this); }
429 :
430 0 : TIntermSwizzle *getAsSwizzleNode() override { return this; };
431 : void traverse(TIntermTraverser *it) override;
432 : bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override;
433 :
434 0 : bool hasSideEffects() const override { return mOperand->hasSideEffects(); }
435 :
436 0 : TIntermTyped *getOperand() { return mOperand; }
437 : void writeOffsetsAsXYZW(TInfoSinkBase *out) const;
438 :
439 : bool hasDuplicateOffsets() const;
440 :
441 : TIntermTyped *fold();
442 :
443 : protected:
444 : TIntermTyped *mOperand;
445 : TVector<int> mSwizzleOffsets;
446 :
447 : private:
448 : void promote();
449 :
450 : TIntermSwizzle(const TIntermSwizzle &node); // Note: not deleted, just private!
451 : };
452 :
453 : //
454 : // Nodes for all the basic binary math operators.
455 : //
456 0 : class TIntermBinary : public TIntermOperator
457 : {
458 : public:
459 : // This constructor determines the type of the binary node based on the operands and op.
460 : TIntermBinary(TOperator op, TIntermTyped *left, TIntermTyped *right);
461 :
462 0 : TIntermTyped *deepCopy() const override { return new TIntermBinary(*this); }
463 :
464 : static TOperator GetMulOpBasedOnOperands(const TType &left, const TType &right);
465 : static TOperator GetMulAssignOpBasedOnOperands(const TType &left, const TType &right);
466 : static TQualifier GetCommaQualifier(int shaderVersion,
467 : const TIntermTyped *left,
468 : const TIntermTyped *right);
469 :
470 0 : TIntermBinary *getAsBinaryNode() override { return this; };
471 : void traverse(TIntermTraverser *it) override;
472 : bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override;
473 :
474 0 : bool hasSideEffects() const override
475 : {
476 0 : return isAssignment() || mLeft->hasSideEffects() || mRight->hasSideEffects();
477 : }
478 :
479 0 : TIntermTyped *getLeft() const { return mLeft; }
480 0 : TIntermTyped *getRight() const { return mRight; }
481 : TIntermTyped *fold(TDiagnostics *diagnostics);
482 :
483 0 : void setAddIndexClamp() { mAddIndexClamp = true; }
484 0 : bool getAddIndexClamp() { return mAddIndexClamp; }
485 :
486 : protected:
487 : TIntermTyped* mLeft;
488 : TIntermTyped* mRight;
489 :
490 : // If set to true, wrap any EOpIndexIndirect with a clamp to bounds.
491 : bool mAddIndexClamp;
492 :
493 : private:
494 : void promote();
495 :
496 : TIntermBinary(const TIntermBinary &node); // Note: not deleted, just private!
497 : };
498 :
499 : //
500 : // Nodes for unary math operators.
501 : //
502 0 : class TIntermUnary : public TIntermOperator
503 : {
504 : public:
505 : TIntermUnary(TOperator op, TIntermTyped *operand);
506 :
507 0 : TIntermTyped *deepCopy() const override { return new TIntermUnary(*this); }
508 :
509 : void traverse(TIntermTraverser *it) override;
510 0 : TIntermUnary *getAsUnaryNode() override { return this; }
511 : bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override;
512 :
513 0 : bool hasSideEffects() const override { return isAssignment() || mOperand->hasSideEffects(); }
514 :
515 0 : TIntermTyped *getOperand() { return mOperand; }
516 : TIntermTyped *fold(TDiagnostics *diagnostics);
517 :
518 0 : void setUseEmulatedFunction() { mUseEmulatedFunction = true; }
519 0 : bool getUseEmulatedFunction() { return mUseEmulatedFunction; }
520 :
521 : protected:
522 : TIntermTyped *mOperand;
523 :
524 : // If set to true, replace the built-in function call with an emulated one
525 : // to work around driver bugs.
526 : bool mUseEmulatedFunction;
527 :
528 : private:
529 : void promote();
530 :
531 : TIntermUnary(const TIntermUnary &node); // note: not deleted, just private!
532 : };
533 :
534 0 : class TFunctionSymbolInfo
535 : {
536 : public:
537 : POOL_ALLOCATOR_NEW_DELETE();
538 0 : TFunctionSymbolInfo() : mId(0) {}
539 :
540 0 : TFunctionSymbolInfo(const TFunctionSymbolInfo &) = default;
541 : TFunctionSymbolInfo &operator=(const TFunctionSymbolInfo &) = default;
542 :
543 : void setFromFunction(const TFunction &function);
544 :
545 0 : void setNameObj(const TName &name) { mName = name; }
546 0 : const TName &getNameObj() const { return mName; }
547 :
548 0 : const TString &getName() const { return mName.getString(); }
549 0 : void setName(const TString &name) { mName.setString(name); }
550 0 : bool isMain() const { return mName.getString() == "main("; }
551 :
552 0 : void setId(int functionId) { mId = functionId; }
553 0 : int getId() const { return mId; }
554 : private:
555 : TName mName;
556 : int mId;
557 : };
558 :
559 : // Node for function definitions.
560 0 : class TIntermFunctionDefinition : public TIntermTyped
561 : {
562 : public:
563 : // TODO(oetuaho@nvidia.com): See if TFunctionSymbolInfo could be added to constructor
564 : // parameters.
565 0 : TIntermFunctionDefinition(const TType &type, TIntermAggregate *parameters, TIntermBlock *body)
566 0 : : TIntermTyped(type), mParameters(parameters), mBody(body)
567 : {
568 0 : ASSERT(parameters != nullptr);
569 0 : ASSERT(body != nullptr);
570 0 : }
571 :
572 0 : TIntermFunctionDefinition *getAsFunctionDefinition() override { return this; }
573 : void traverse(TIntermTraverser *it) override;
574 : bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override;
575 :
576 0 : TIntermTyped *deepCopy() const override
577 : {
578 0 : UNREACHABLE();
579 : return nullptr;
580 : }
581 0 : bool hasSideEffects() const override
582 : {
583 0 : UNREACHABLE();
584 : return true;
585 : }
586 :
587 0 : TIntermAggregate *getFunctionParameters() const { return mParameters; }
588 0 : TIntermBlock *getBody() const { return mBody; }
589 :
590 0 : TFunctionSymbolInfo *getFunctionSymbolInfo() { return &mFunctionInfo; }
591 0 : const TFunctionSymbolInfo *getFunctionSymbolInfo() const { return &mFunctionInfo; }
592 :
593 : private:
594 : TIntermAggregate *mParameters;
595 : TIntermBlock *mBody;
596 :
597 : TFunctionSymbolInfo mFunctionInfo;
598 : };
599 :
600 : typedef TVector<TIntermNode *> TIntermSequence;
601 : typedef TVector<int> TQualifierList;
602 :
603 : // Interface for node classes that have an arbitrarily sized set of children.
604 : class TIntermAggregateBase
605 : {
606 : public:
607 0 : virtual ~TIntermAggregateBase() {}
608 :
609 : virtual TIntermSequence *getSequence() = 0;
610 : virtual const TIntermSequence *getSequence() const = 0;
611 :
612 : bool replaceChildNodeWithMultiple(TIntermNode *original, const TIntermSequence &replacements);
613 : bool insertChildNodes(TIntermSequence::size_type position, const TIntermSequence &insertions);
614 :
615 : protected:
616 0 : TIntermAggregateBase() {}
617 :
618 : bool replaceChildNodeInternal(TIntermNode *original, TIntermNode *replacement);
619 : };
620 :
621 : //
622 : // Nodes that operate on an arbitrary sized set of children.
623 : //
624 : class TIntermAggregate : public TIntermOperator, public TIntermAggregateBase
625 : {
626 : public:
627 0 : TIntermAggregate()
628 0 : : TIntermOperator(EOpNull),
629 : mUserDefined(false),
630 : mUseEmulatedFunction(false),
631 0 : mGotPrecisionFromChildren(false)
632 : {
633 0 : }
634 0 : TIntermAggregate(TOperator op)
635 0 : : TIntermOperator(op),
636 : mUserDefined(false),
637 : mUseEmulatedFunction(false),
638 0 : mGotPrecisionFromChildren(false)
639 : {
640 0 : }
641 0 : ~TIntermAggregate() { }
642 :
643 : // Note: only supported for nodes that can be a part of an expression.
644 0 : TIntermTyped *deepCopy() const override { return new TIntermAggregate(*this); }
645 :
646 0 : void setOp(TOperator op) { mOp = op; }
647 :
648 0 : TIntermAggregate *getAsAggregate() override { return this; }
649 : void traverse(TIntermTraverser *it) override;
650 : bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override;
651 :
652 : // Conservatively assume function calls and other aggregate operators have side-effects
653 0 : bool hasSideEffects() const override { return true; }
654 : TIntermTyped *fold(TDiagnostics *diagnostics);
655 :
656 0 : TIntermSequence *getSequence() override { return &mSequence; }
657 0 : const TIntermSequence *getSequence() const override { return &mSequence; }
658 :
659 0 : void setUserDefined() { mUserDefined = true; }
660 0 : bool isUserDefined() const { return mUserDefined; }
661 :
662 0 : void setUseEmulatedFunction() { mUseEmulatedFunction = true; }
663 0 : bool getUseEmulatedFunction() { return mUseEmulatedFunction; }
664 :
665 : bool areChildrenConstQualified();
666 : void setPrecisionFromChildren();
667 : void setBuiltInFunctionPrecision();
668 :
669 : // Returns true if changing parameter precision may affect the return value.
670 0 : bool gotPrecisionFromChildren() const { return mGotPrecisionFromChildren; }
671 :
672 0 : TFunctionSymbolInfo *getFunctionSymbolInfo() { return &mFunctionInfo; }
673 0 : const TFunctionSymbolInfo *getFunctionSymbolInfo() const { return &mFunctionInfo; }
674 :
675 : protected:
676 : TIntermSequence mSequence;
677 : bool mUserDefined; // used for user defined function names
678 :
679 : // If set to true, replace the built-in function call with an emulated one
680 : // to work around driver bugs.
681 : bool mUseEmulatedFunction;
682 :
683 : bool mGotPrecisionFromChildren;
684 :
685 : TFunctionSymbolInfo mFunctionInfo;
686 :
687 : private:
688 : TIntermAggregate(const TIntermAggregate &node); // note: not deleted, just private!
689 : };
690 :
691 : // A list of statements. Either the root node which contains declarations and function definitions,
692 : // or a block that can be marked with curly braces {}.
693 : class TIntermBlock : public TIntermNode, public TIntermAggregateBase
694 : {
695 : public:
696 0 : TIntermBlock() : TIntermNode() {}
697 0 : ~TIntermBlock() {}
698 :
699 0 : TIntermBlock *getAsBlock() override { return this; }
700 : void traverse(TIntermTraverser *it) override;
701 : bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override;
702 :
703 : // Only intended for initially building the block.
704 : void appendStatement(TIntermNode *statement);
705 :
706 0 : TIntermSequence *getSequence() override { return &mStatements; }
707 0 : const TIntermSequence *getSequence() const override { return &mStatements; }
708 :
709 : protected:
710 : TIntermSequence mStatements;
711 : };
712 :
713 : // Struct, interface block or variable declaration. Can contain multiple variable declarators.
714 : class TIntermDeclaration : public TIntermNode, public TIntermAggregateBase
715 : {
716 : public:
717 0 : TIntermDeclaration() : TIntermNode() {}
718 0 : ~TIntermDeclaration() {}
719 :
720 0 : TIntermDeclaration *getAsDeclarationNode() override { return this; }
721 : void traverse(TIntermTraverser *it) override;
722 : bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override;
723 :
724 : // Only intended for initially building the declaration.
725 : // The declarator node should be either TIntermSymbol or TIntermBinary with op set to
726 : // EOpInitialize.
727 : void appendDeclarator(TIntermTyped *declarator);
728 :
729 0 : TIntermSequence *getSequence() override { return &mDeclarators; }
730 0 : const TIntermSequence *getSequence() const override { return &mDeclarators; }
731 : protected:
732 : TIntermSequence mDeclarators;
733 : };
734 :
735 : // For ternary operators like a ? b : c.
736 0 : class TIntermTernary : public TIntermTyped
737 : {
738 : public:
739 : TIntermTernary(TIntermTyped *cond, TIntermTyped *trueExpression, TIntermTyped *falseExpression);
740 :
741 : void traverse(TIntermTraverser *it) override;
742 : bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override;
743 :
744 0 : TIntermTyped *getCondition() const { return mCondition; }
745 0 : TIntermTyped *getTrueExpression() const { return mTrueExpression; }
746 0 : TIntermTyped *getFalseExpression() const { return mFalseExpression; }
747 0 : TIntermTernary *getAsTernaryNode() override { return this; }
748 :
749 0 : TIntermTyped *deepCopy() const override { return new TIntermTernary(*this); }
750 :
751 0 : bool hasSideEffects() const override
752 : {
753 0 : return mCondition->hasSideEffects() || mTrueExpression->hasSideEffects() ||
754 0 : mFalseExpression->hasSideEffects();
755 : }
756 :
757 : static TQualifier DetermineQualifier(TIntermTyped *cond,
758 : TIntermTyped *trueExpression,
759 : TIntermTyped *falseExpression);
760 :
761 : private:
762 : TIntermTernary(const TIntermTernary &node); // Note: not deleted, just private!
763 :
764 : TIntermTyped *mCondition;
765 : TIntermTyped *mTrueExpression;
766 : TIntermTyped *mFalseExpression;
767 : };
768 :
769 0 : class TIntermIfElse : public TIntermNode
770 : {
771 : public:
772 0 : TIntermIfElse(TIntermTyped *cond, TIntermBlock *trueB, TIntermBlock *falseB)
773 0 : : TIntermNode(), mCondition(cond), mTrueBlock(trueB), mFalseBlock(falseB)
774 : {
775 0 : }
776 :
777 : void traverse(TIntermTraverser *it) override;
778 : bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override;
779 :
780 0 : TIntermTyped *getCondition() const { return mCondition; }
781 0 : TIntermBlock *getTrueBlock() const { return mTrueBlock; }
782 0 : TIntermBlock *getFalseBlock() const { return mFalseBlock; }
783 0 : TIntermIfElse *getAsIfElseNode() override { return this; }
784 :
785 : protected:
786 : TIntermTyped *mCondition;
787 : TIntermBlock *mTrueBlock;
788 : TIntermBlock *mFalseBlock;
789 : };
790 :
791 : //
792 : // Switch statement.
793 : //
794 0 : class TIntermSwitch : public TIntermNode
795 : {
796 : public:
797 0 : TIntermSwitch(TIntermTyped *init, TIntermBlock *statementList)
798 0 : : TIntermNode(), mInit(init), mStatementList(statementList)
799 : {
800 0 : }
801 :
802 : void traverse(TIntermTraverser *it) override;
803 : bool replaceChildNode(
804 : TIntermNode *original, TIntermNode *replacement) override;
805 :
806 0 : TIntermSwitch *getAsSwitchNode() override { return this; }
807 :
808 0 : TIntermTyped *getInit() { return mInit; }
809 0 : TIntermBlock *getStatementList() { return mStatementList; }
810 0 : void setStatementList(TIntermBlock *statementList) { mStatementList = statementList; }
811 :
812 : protected:
813 : TIntermTyped *mInit;
814 : TIntermBlock *mStatementList;
815 : };
816 :
817 : //
818 : // Case label.
819 : //
820 0 : class TIntermCase : public TIntermNode
821 : {
822 : public:
823 0 : TIntermCase(TIntermTyped *condition)
824 0 : : TIntermNode(),
825 0 : mCondition(condition)
826 : {
827 0 : }
828 :
829 : void traverse(TIntermTraverser *it) override;
830 : bool replaceChildNode(
831 : TIntermNode *original, TIntermNode *replacement) override;
832 :
833 0 : TIntermCase *getAsCaseNode() override { return this; }
834 :
835 0 : bool hasCondition() const { return mCondition != nullptr; }
836 0 : TIntermTyped *getCondition() const { return mCondition; }
837 :
838 : protected:
839 : TIntermTyped *mCondition;
840 : };
841 :
842 : enum Visit
843 : {
844 : PreVisit,
845 : InVisit,
846 : PostVisit
847 : };
848 :
849 : //
850 : // For traversing the tree. User should derive from this class overriding the visit functions,
851 : // and then pass an object of the subclass to a traverse method of a node.
852 : //
853 : // The traverse*() functions may also be overridden do other bookkeeping on the tree to provide
854 : // contextual information to the visit functions, such as whether the node is the target of an
855 : // assignment.
856 : //
857 : // When using this, just fill in the methods for nodes you want visited.
858 : // Return false from a pre-visit to skip visiting that node's subtree.
859 : //
860 : class TIntermTraverser : angle::NonCopyable
861 : {
862 : public:
863 0 : POOL_ALLOCATOR_NEW_DELETE();
864 : TIntermTraverser(bool preVisit, bool inVisit, bool postVisit);
865 : virtual ~TIntermTraverser();
866 :
867 0 : virtual void visitSymbol(TIntermSymbol *node) {}
868 0 : virtual void visitRaw(TIntermRaw *node) {}
869 0 : virtual void visitConstantUnion(TIntermConstantUnion *node) {}
870 0 : virtual bool visitSwizzle(Visit visit, TIntermSwizzle *node) { return true; }
871 0 : virtual bool visitBinary(Visit visit, TIntermBinary *node) { return true; }
872 0 : virtual bool visitUnary(Visit visit, TIntermUnary *node) { return true; }
873 0 : virtual bool visitTernary(Visit visit, TIntermTernary *node) { return true; }
874 0 : virtual bool visitIfElse(Visit visit, TIntermIfElse *node) { return true; }
875 0 : virtual bool visitSwitch(Visit visit, TIntermSwitch *node) { return true; }
876 0 : virtual bool visitCase(Visit visit, TIntermCase *node) { return true; }
877 0 : virtual bool visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node)
878 : {
879 0 : return true;
880 : }
881 0 : virtual bool visitAggregate(Visit visit, TIntermAggregate *node) { return true; }
882 0 : virtual bool visitBlock(Visit visit, TIntermBlock *node) { return true; }
883 0 : virtual bool visitDeclaration(Visit visit, TIntermDeclaration *node) { return true; }
884 0 : virtual bool visitLoop(Visit visit, TIntermLoop *node) { return true; }
885 0 : virtual bool visitBranch(Visit visit, TIntermBranch *node) { return true; }
886 :
887 : // The traverse functions contain logic for iterating over the children of the node
888 : // and calling the visit functions in the appropriate places. They also track some
889 : // context that may be used by the visit functions.
890 : virtual void traverseSymbol(TIntermSymbol *node);
891 : virtual void traverseRaw(TIntermRaw *node);
892 : virtual void traverseConstantUnion(TIntermConstantUnion *node);
893 : virtual void traverseSwizzle(TIntermSwizzle *node);
894 : virtual void traverseBinary(TIntermBinary *node);
895 : virtual void traverseUnary(TIntermUnary *node);
896 : virtual void traverseTernary(TIntermTernary *node);
897 : virtual void traverseIfElse(TIntermIfElse *node);
898 : virtual void traverseSwitch(TIntermSwitch *node);
899 : virtual void traverseCase(TIntermCase *node);
900 : virtual void traverseFunctionDefinition(TIntermFunctionDefinition *node);
901 : virtual void traverseAggregate(TIntermAggregate *node);
902 : virtual void traverseBlock(TIntermBlock *node);
903 : virtual void traverseDeclaration(TIntermDeclaration *node);
904 : virtual void traverseLoop(TIntermLoop *node);
905 : virtual void traverseBranch(TIntermBranch *node);
906 :
907 0 : int getMaxDepth() const { return mMaxDepth; }
908 :
909 : // Return the original name if hash function pointer is NULL;
910 : // otherwise return the hashed name.
911 : static TString hash(const TString &name, ShHashFunction64 hashFunction);
912 :
913 : // If traversers need to replace nodes, they can add the replacements in
914 : // mReplacements/mMultiReplacements during traversal and the user of the traverser should call
915 : // this function after traversal to perform them.
916 : void updateTree();
917 :
918 : // Start creating temporary symbols from the given temporary symbol index + 1.
919 : void useTemporaryIndex(unsigned int *temporaryIndex);
920 :
921 : protected:
922 0 : void incrementDepth(TIntermNode *current)
923 : {
924 0 : mDepth++;
925 0 : mMaxDepth = std::max(mMaxDepth, mDepth);
926 0 : mPath.push_back(current);
927 0 : }
928 :
929 0 : void decrementDepth()
930 : {
931 0 : mDepth--;
932 0 : mPath.pop_back();
933 0 : }
934 :
935 0 : TIntermNode *getParentNode()
936 : {
937 0 : return mPath.size() == 0 ? NULL : mPath.back();
938 : }
939 :
940 : // Return the nth ancestor of the node being traversed. getAncestorNode(0) == getParentNode()
941 0 : TIntermNode *getAncestorNode(unsigned int n)
942 : {
943 0 : if (mPath.size() > n)
944 : {
945 0 : return mPath[mPath.size() - n - 1u];
946 : }
947 0 : return nullptr;
948 : }
949 :
950 : void pushParentBlock(TIntermBlock *node);
951 : void incrementParentBlockPos();
952 : void popParentBlock();
953 :
954 : bool parentNodeIsBlock()
955 : {
956 : return !mParentBlockStack.empty() && getParentNode() == mParentBlockStack.back().node;
957 : }
958 :
959 : // To replace a single node with multiple nodes on the parent aggregate node
960 0 : struct NodeReplaceWithMultipleEntry
961 : {
962 0 : NodeReplaceWithMultipleEntry(TIntermAggregateBase *_parent,
963 : TIntermNode *_original,
964 : TIntermSequence _replacements)
965 0 : : parent(_parent), original(_original), replacements(_replacements)
966 : {
967 0 : }
968 :
969 : TIntermAggregateBase *parent;
970 : TIntermNode *original;
971 : TIntermSequence replacements;
972 : };
973 :
974 : // To insert multiple nodes on the parent aggregate node
975 0 : struct NodeInsertMultipleEntry
976 : {
977 0 : NodeInsertMultipleEntry(TIntermBlock *_parent,
978 : TIntermSequence::size_type _position,
979 : TIntermSequence _insertionsBefore,
980 : TIntermSequence _insertionsAfter)
981 0 : : parent(_parent),
982 : position(_position),
983 : insertionsBefore(_insertionsBefore),
984 0 : insertionsAfter(_insertionsAfter)
985 : {
986 0 : }
987 :
988 : TIntermBlock *parent;
989 : TIntermSequence::size_type position;
990 : TIntermSequence insertionsBefore;
991 : TIntermSequence insertionsAfter;
992 : };
993 :
994 : // Helper to insert statements in the parent block (sequence) of the node currently being traversed.
995 : // The statements will be inserted before the node being traversed once updateTree is called.
996 : // Should only be called during PreVisit or PostVisit from sequence nodes.
997 : // Note that inserting more than one set of nodes to the same parent node on a single updateTree call is not
998 : // supported.
999 : void insertStatementsInParentBlock(const TIntermSequence &insertions);
1000 :
1001 : // Same as above, but supports simultaneous insertion of statements before and after the node
1002 : // currently being traversed.
1003 : void insertStatementsInParentBlock(const TIntermSequence &insertionsBefore,
1004 : const TIntermSequence &insertionsAfter);
1005 :
1006 : // Helper to insert a single statement.
1007 : void insertStatementInParentBlock(TIntermNode *statement);
1008 :
1009 : // Helper to create a temporary symbol node with the given qualifier.
1010 : TIntermSymbol *createTempSymbol(const TType &type, TQualifier qualifier);
1011 : // Helper to create a temporary symbol node.
1012 : TIntermSymbol *createTempSymbol(const TType &type);
1013 : // Create a node that declares but doesn't initialize a temporary symbol.
1014 : TIntermDeclaration *createTempDeclaration(const TType &type);
1015 : // Create a node that initializes the current temporary symbol with initializer having the given qualifier.
1016 : TIntermDeclaration *createTempInitDeclaration(TIntermTyped *initializer, TQualifier qualifier);
1017 : // Create a node that initializes the current temporary symbol with initializer.
1018 : TIntermDeclaration *createTempInitDeclaration(TIntermTyped *initializer);
1019 : // Create a node that assigns rightNode to the current temporary symbol.
1020 : TIntermBinary *createTempAssignment(TIntermTyped *rightNode);
1021 : // Increment temporary symbol index.
1022 : void nextTemporaryIndex();
1023 :
1024 : enum class OriginalNode
1025 : {
1026 : BECOMES_CHILD,
1027 : IS_DROPPED
1028 : };
1029 :
1030 : void clearReplacementQueue();
1031 : void queueReplacement(TIntermNode *original,
1032 : TIntermNode *replacement,
1033 : OriginalNode originalStatus);
1034 : void queueReplacementWithParent(TIntermNode *parent,
1035 : TIntermNode *original,
1036 : TIntermNode *replacement,
1037 : OriginalNode originalStatus);
1038 :
1039 : const bool preVisit;
1040 : const bool inVisit;
1041 : const bool postVisit;
1042 :
1043 : int mDepth;
1044 : int mMaxDepth;
1045 :
1046 : // All the nodes from root to the current node's parent during traversing.
1047 : TVector<TIntermNode *> mPath;
1048 :
1049 : bool mInGlobalScope;
1050 :
1051 : // During traversing, save all the changes that need to happen into
1052 : // mReplacements/mMultiReplacements, then do them by calling updateTree().
1053 : // Multi replacements are processed after single replacements.
1054 : std::vector<NodeReplaceWithMultipleEntry> mMultiReplacements;
1055 : std::vector<NodeInsertMultipleEntry> mInsertions;
1056 :
1057 : private:
1058 : // To replace a single node with another on the parent node
1059 : struct NodeUpdateEntry
1060 : {
1061 0 : NodeUpdateEntry(TIntermNode *_parent,
1062 : TIntermNode *_original,
1063 : TIntermNode *_replacement,
1064 : bool _originalBecomesChildOfReplacement)
1065 0 : : parent(_parent),
1066 : original(_original),
1067 : replacement(_replacement),
1068 0 : originalBecomesChildOfReplacement(_originalBecomesChildOfReplacement)
1069 : {
1070 0 : }
1071 :
1072 : TIntermNode *parent;
1073 : TIntermNode *original;
1074 : TIntermNode *replacement;
1075 : bool originalBecomesChildOfReplacement;
1076 : };
1077 :
1078 : struct ParentBlock
1079 : {
1080 0 : ParentBlock(TIntermBlock *nodeIn, TIntermSequence::size_type posIn)
1081 0 : : node(nodeIn), pos(posIn)
1082 : {
1083 0 : }
1084 :
1085 : TIntermBlock *node;
1086 : TIntermSequence::size_type pos;
1087 : };
1088 :
1089 : std::vector<NodeUpdateEntry> mReplacements;
1090 :
1091 : // All the code blocks from the root to the current node's parent during traversal.
1092 : std::vector<ParentBlock> mParentBlockStack;
1093 :
1094 : unsigned int *mTemporaryIndex;
1095 : };
1096 :
1097 : // Traverser parent class that tracks where a node is a destination of a write operation and so is
1098 : // required to be an l-value.
1099 : class TLValueTrackingTraverser : public TIntermTraverser
1100 : {
1101 : public:
1102 0 : TLValueTrackingTraverser(bool preVisit,
1103 : bool inVisit,
1104 : bool postVisit,
1105 : const TSymbolTable &symbolTable,
1106 : int shaderVersion)
1107 0 : : TIntermTraverser(preVisit, inVisit, postVisit),
1108 : mOperatorRequiresLValue(false),
1109 : mInFunctionCallOutParameter(false),
1110 : mSymbolTable(symbolTable),
1111 0 : mShaderVersion(shaderVersion)
1112 : {
1113 0 : }
1114 0 : virtual ~TLValueTrackingTraverser() {}
1115 :
1116 : void traverseBinary(TIntermBinary *node) final;
1117 : void traverseUnary(TIntermUnary *node) final;
1118 : void traverseFunctionDefinition(TIntermFunctionDefinition *node) final;
1119 : void traverseAggregate(TIntermAggregate *node) final;
1120 :
1121 : protected:
1122 0 : bool isLValueRequiredHere() const
1123 : {
1124 0 : return mOperatorRequiresLValue || mInFunctionCallOutParameter;
1125 : }
1126 :
1127 : // Return true if the prototype or definition of the function being called has been encountered
1128 : // during traversal.
1129 : bool isInFunctionMap(const TIntermAggregate *callNode) const;
1130 :
1131 : private:
1132 : // Track whether an l-value is required in the node that is currently being traversed by the
1133 : // surrounding operator.
1134 : // Use isLValueRequiredHere to check all conditions which require an l-value.
1135 0 : void setOperatorRequiresLValue(bool lValueRequired)
1136 : {
1137 0 : mOperatorRequiresLValue = lValueRequired;
1138 0 : }
1139 0 : bool operatorRequiresLValue() const { return mOperatorRequiresLValue; }
1140 :
1141 : // Add a function encountered during traversal to the function map.
1142 : void addToFunctionMap(const TName &name, TIntermSequence *paramSequence);
1143 :
1144 : // Return the parameters sequence from the function definition or prototype.
1145 : TIntermSequence *getFunctionParameters(const TIntermAggregate *callNode);
1146 :
1147 : // Track whether an l-value is required inside a function call.
1148 : void setInFunctionCallOutParameter(bool inOutParameter);
1149 : bool isInFunctionCallOutParameter() const;
1150 :
1151 : bool mOperatorRequiresLValue;
1152 : bool mInFunctionCallOutParameter;
1153 :
1154 : struct TNameComparator
1155 : {
1156 0 : bool operator()(const TName &a, const TName &b) const
1157 : {
1158 0 : int compareResult = a.getString().compare(b.getString());
1159 0 : if (compareResult != 0)
1160 0 : return compareResult < 0;
1161 : // Internal functions may have same names as non-internal functions.
1162 0 : return !a.isInternal() && b.isInternal();
1163 : }
1164 : };
1165 :
1166 : // Map from mangled function names to their parameter sequences
1167 : TMap<TName, TIntermSequence *, TNameComparator> mFunctionMap;
1168 :
1169 : const TSymbolTable &mSymbolTable;
1170 : const int mShaderVersion;
1171 : };
1172 :
1173 : //
1174 : // For traversing the tree, and computing max depth.
1175 : // Takes a maximum depth limit to prevent stack overflow.
1176 : //
1177 0 : class TMaxDepthTraverser : public TIntermTraverser
1178 : {
1179 : public:
1180 0 : POOL_ALLOCATOR_NEW_DELETE();
1181 0 : TMaxDepthTraverser(int depthLimit)
1182 0 : : TIntermTraverser(true, true, false),
1183 0 : mDepthLimit(depthLimit) { }
1184 :
1185 0 : bool visitBinary(Visit, TIntermBinary *) override { return depthCheck(); }
1186 0 : bool visitUnary(Visit, TIntermUnary *) override { return depthCheck(); }
1187 0 : bool visitTernary(Visit, TIntermTernary *) override { return depthCheck(); }
1188 0 : bool visitIfElse(Visit, TIntermIfElse *) override { return depthCheck(); }
1189 0 : bool visitAggregate(Visit, TIntermAggregate *) override { return depthCheck(); }
1190 0 : bool visitBlock(Visit, TIntermBlock *) override { return depthCheck(); }
1191 0 : bool visitLoop(Visit, TIntermLoop *) override { return depthCheck(); }
1192 0 : bool visitBranch(Visit, TIntermBranch *) override { return depthCheck(); }
1193 :
1194 : protected:
1195 0 : bool depthCheck() const { return mMaxDepth < mDepthLimit; }
1196 :
1197 : int mDepthLimit;
1198 : };
1199 :
1200 : } // namespace sh
1201 :
1202 : #endif // COMPILER_TRANSLATOR_INTERMNODE_H_
|