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/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(); |
34 | 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 | |
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 | |
53 | void SplitSequenceOperatorTraverser::nextIteration() |
54 | { |
55 | mFoundExpressionToSplit = false; |
56 | mInsideSequenceOperator = 0; |
57 | } |
58 | |
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 | |
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 | |
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 | |
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 | |
150 | void SplitSequenceOperator(TIntermNode *root, int patternsToSplitMask, TSymbolTable *symbolTable) |
151 | { |
152 | SplitSequenceOperatorTraverser traverser(patternsToSplitMask, symbolTable); |
153 | // Separate one expression at a time, and reset the traverser between iterations. |
154 | do |
155 | { |
156 | traverser.nextIteration(); |
157 | root->traverse(&traverser); |
158 | if (traverser.foundExpressionToSplit()) |
159 | traverser.updateTree(); |
160 | } while (traverser.foundExpressionToSplit()); |
161 | } |
162 | |
163 | } // namespace sh |
164 | |