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