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