Line data Source code
1 : //
2 : // Copyright (c) 2016 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 : // SplitSequenceOperator is an AST traverser that detects sequence operator expressions that
7 : // go through further AST transformations that generate statements, and splits them so that
8 : // possible side effects of earlier parts of the sequence operator expression are guaranteed to be
9 : // evaluated before the latter parts of the sequence operator expression are evaluated.
10 : //
11 :
12 : #include "compiler/translator/SplitSequenceOperator.h"
13 :
14 : #include "compiler/translator/IntermNode.h"
15 : #include "compiler/translator/IntermNodePatternMatcher.h"
16 :
17 : namespace sh
18 : {
19 :
20 : namespace
21 : {
22 :
23 0 : class SplitSequenceOperatorTraverser : public TLValueTrackingTraverser
24 : {
25 : public:
26 : SplitSequenceOperatorTraverser(unsigned int patternsToSplitMask,
27 : const TSymbolTable &symbolTable,
28 : int shaderVersion);
29 :
30 : bool visitBinary(Visit visit, TIntermBinary *node) override;
31 : bool visitAggregate(Visit visit, TIntermAggregate *node) override;
32 : bool visitTernary(Visit visit, TIntermTernary *node) override;
33 :
34 : void nextIteration();
35 0 : bool foundExpressionToSplit() const { return mFoundExpressionToSplit; }
36 :
37 : protected:
38 : // Marked to true once an operation that needs to be hoisted out of the expression has been
39 : // found. After that, no more AST updates are performed on that traversal.
40 : bool mFoundExpressionToSplit;
41 : int mInsideSequenceOperator;
42 :
43 : IntermNodePatternMatcher mPatternToSplitMatcher;
44 : };
45 :
46 0 : SplitSequenceOperatorTraverser::SplitSequenceOperatorTraverser(unsigned int patternsToSplitMask,
47 : const TSymbolTable &symbolTable,
48 0 : int shaderVersion)
49 : : TLValueTrackingTraverser(true, false, true, symbolTable, shaderVersion),
50 : mFoundExpressionToSplit(false),
51 : mInsideSequenceOperator(0),
52 0 : mPatternToSplitMatcher(patternsToSplitMask)
53 : {
54 0 : }
55 :
56 0 : void SplitSequenceOperatorTraverser::nextIteration()
57 : {
58 0 : mFoundExpressionToSplit = false;
59 0 : mInsideSequenceOperator = 0;
60 0 : nextTemporaryIndex();
61 0 : }
62 :
63 0 : bool SplitSequenceOperatorTraverser::visitAggregate(Visit visit, TIntermAggregate *node)
64 : {
65 0 : if (mFoundExpressionToSplit)
66 0 : return false;
67 :
68 0 : if (mInsideSequenceOperator > 0 && visit == PreVisit)
69 : {
70 : // Detect expressions that need to be simplified
71 0 : mFoundExpressionToSplit = mPatternToSplitMatcher.match(node, getParentNode());
72 0 : return !mFoundExpressionToSplit;
73 : }
74 :
75 0 : return true;
76 : }
77 :
78 0 : bool SplitSequenceOperatorTraverser::visitBinary(Visit visit, TIntermBinary *node)
79 : {
80 0 : if (node->getOp() == EOpComma)
81 : {
82 0 : if (visit == PreVisit)
83 : {
84 0 : if (mFoundExpressionToSplit)
85 : {
86 0 : return false;
87 : }
88 0 : mInsideSequenceOperator++;
89 : }
90 0 : else if (visit == PostVisit)
91 : {
92 : // Split sequence operators starting from the outermost one to preserve correct
93 : // execution order.
94 0 : if (mFoundExpressionToSplit && mInsideSequenceOperator == 1)
95 : {
96 : // Move the left side operand into a separate statement in the parent block.
97 0 : TIntermSequence insertions;
98 0 : insertions.push_back(node->getLeft());
99 0 : insertStatementsInParentBlock(insertions);
100 : // Replace the comma node with its right side operand.
101 0 : queueReplacement(node, node->getRight(), OriginalNode::IS_DROPPED);
102 : }
103 0 : mInsideSequenceOperator--;
104 : }
105 0 : return true;
106 : }
107 :
108 0 : if (mFoundExpressionToSplit)
109 0 : return false;
110 :
111 0 : if (mInsideSequenceOperator > 0 && visit == PreVisit)
112 : {
113 : // Detect expressions that need to be simplified
114 0 : mFoundExpressionToSplit =
115 0 : mPatternToSplitMatcher.match(node, getParentNode(), isLValueRequiredHere());
116 0 : return !mFoundExpressionToSplit;
117 : }
118 :
119 0 : return true;
120 : }
121 :
122 0 : bool SplitSequenceOperatorTraverser::visitTernary(Visit visit, TIntermTernary *node)
123 : {
124 0 : if (mFoundExpressionToSplit)
125 0 : return false;
126 :
127 0 : if (mInsideSequenceOperator > 0 && visit == PreVisit)
128 : {
129 : // Detect expressions that need to be simplified
130 0 : mFoundExpressionToSplit = mPatternToSplitMatcher.match(node);
131 0 : return !mFoundExpressionToSplit;
132 : }
133 :
134 0 : return true;
135 : }
136 :
137 : } // namespace
138 :
139 0 : void SplitSequenceOperator(TIntermNode *root,
140 : int patternsToSplitMask,
141 : unsigned int *temporaryIndex,
142 : const TSymbolTable &symbolTable,
143 : int shaderVersion)
144 : {
145 0 : SplitSequenceOperatorTraverser traverser(patternsToSplitMask, symbolTable, shaderVersion);
146 0 : ASSERT(temporaryIndex != nullptr);
147 0 : traverser.useTemporaryIndex(temporaryIndex);
148 : // Separate one expression at a time, and reset the traverser between iterations.
149 0 : do
150 : {
151 0 : traverser.nextIteration();
152 0 : root->traverse(&traverser);
153 0 : if (traverser.foundExpressionToSplit())
154 0 : traverser.updateTree();
155 : } while (traverser.foundExpressionToSplit());
156 0 : }
157 :
158 : } // namespace sh
|