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