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 // IntermNodePatternMatcher is a helper class for matching node trees to given patterns.
7 // It can be used whenever the same checks for certain node structures are common to multiple AST
8 // traversers.
9 //
10
11 #include "compiler/translator/tree_util/IntermNodePatternMatcher.h"
12
13 #include "compiler/translator/IntermNode.h"
14 #include "compiler/translator/SymbolTable.h"
15 #include "compiler/translator/util.h"
16
17 namespace sh
18 {
19
20 namespace
21 {
22
ContainsMatrixNode(const TIntermSequence & sequence)23 bool ContainsMatrixNode(const TIntermSequence &sequence)
24 {
25 for (size_t ii = 0; ii < sequence.size(); ++ii)
26 {
27 TIntermTyped *node = sequence[ii]->getAsTyped();
28 if (node && node->isMatrix())
29 return true;
30 }
31 return false;
32 }
33
ContainsVectorNode(const TIntermSequence & sequence)34 bool ContainsVectorNode(const TIntermSequence &sequence)
35 {
36 for (size_t ii = 0; ii < sequence.size(); ++ii)
37 {
38 TIntermTyped *node = sequence[ii]->getAsTyped();
39 if (node && node->isVector())
40 return true;
41 }
42 return false;
43 }
44
45 } // anonymous namespace
46
IntermNodePatternMatcher(const unsigned int mask)47 IntermNodePatternMatcher::IntermNodePatternMatcher(const unsigned int mask) : mMask(mask) {}
48
49 // static
IsDynamicIndexingOfNonSSBOVectorOrMatrix(TIntermBinary * node)50 bool IntermNodePatternMatcher::IsDynamicIndexingOfNonSSBOVectorOrMatrix(TIntermBinary *node)
51 {
52 return IsDynamicIndexingOfVectorOrMatrix(node) && !IsInShaderStorageBlock(node->getLeft());
53 }
54
55 // static
IsDynamicIndexingOfVectorOrMatrix(TIntermBinary * node)56 bool IntermNodePatternMatcher::IsDynamicIndexingOfVectorOrMatrix(TIntermBinary *node)
57 {
58 return node->getOp() == EOpIndexIndirect && !node->getLeft()->isArray() &&
59 node->getLeft()->getBasicType() != EbtStruct;
60 }
61
62 // static
IsDynamicIndexingOfSwizzledVector(TIntermBinary * node)63 bool IntermNodePatternMatcher::IsDynamicIndexingOfSwizzledVector(TIntermBinary *node)
64 {
65 return IsDynamicIndexingOfVectorOrMatrix(node) && node->getLeft()->getAsSwizzleNode();
66 }
67
matchInternal(TIntermBinary * node,TIntermNode * parentNode) const68 bool IntermNodePatternMatcher::matchInternal(TIntermBinary *node, TIntermNode *parentNode) const
69 {
70 if ((mMask & kExpressionReturningArray) != 0)
71 {
72 if (node->isArray() && node->getOp() == EOpAssign && parentNode != nullptr &&
73 !parentNode->getAsBlock())
74 {
75 return true;
76 }
77 }
78
79 if ((mMask & kUnfoldedShortCircuitExpression) != 0)
80 {
81 if (node->getRight()->hasSideEffects() &&
82 (node->getOp() == EOpLogicalOr || node->getOp() == EOpLogicalAnd))
83 {
84 return true;
85 }
86 }
87 return false;
88 }
89
match(TIntermUnary * node) const90 bool IntermNodePatternMatcher::match(TIntermUnary *node) const
91 {
92 if ((mMask & kArrayLengthMethod) != 0)
93 {
94 if (node->getOp() == EOpArrayLength)
95 {
96 return true;
97 }
98 }
99 return false;
100 }
101
match(TIntermBinary * node,TIntermNode * parentNode) const102 bool IntermNodePatternMatcher::match(TIntermBinary *node, TIntermNode *parentNode) const
103 {
104 // L-value tracking information is needed to check for dynamic indexing in L-value.
105 // Traversers that don't track l-values can still use this class and match binary nodes with
106 // this variation of this method if they don't need to check for dynamic indexing in l-values.
107 ASSERT((mMask & kDynamicIndexingOfVectorOrMatrixInLValue) == 0);
108 return matchInternal(node, parentNode);
109 }
110
match(TIntermBinary * node,TIntermNode * parentNode,bool isLValueRequiredHere) const111 bool IntermNodePatternMatcher::match(TIntermBinary *node,
112 TIntermNode *parentNode,
113 bool isLValueRequiredHere) const
114 {
115 if (matchInternal(node, parentNode))
116 {
117 return true;
118 }
119 if ((mMask & kDynamicIndexingOfVectorOrMatrixInLValue) != 0)
120 {
121 if (isLValueRequiredHere && IsDynamicIndexingOfVectorOrMatrix(node))
122 {
123 return true;
124 }
125 }
126 return false;
127 }
128
match(TIntermAggregate * node,TIntermNode * parentNode) const129 bool IntermNodePatternMatcher::match(TIntermAggregate *node, TIntermNode *parentNode) const
130 {
131 if ((mMask & kExpressionReturningArray) != 0)
132 {
133 if (parentNode != nullptr)
134 {
135 TIntermBinary *parentBinary = parentNode->getAsBinaryNode();
136 bool parentIsAssignment =
137 (parentBinary != nullptr &&
138 (parentBinary->getOp() == EOpAssign || parentBinary->getOp() == EOpInitialize));
139
140 if (node->getType().isArray() && !parentIsAssignment &&
141 (node->isConstructor() || node->isFunctionCall() ||
142 (BuiltInGroup::IsBuiltIn(node->getOp()) &&
143 !BuiltInGroup::IsMath(node->getOp()))) &&
144 !parentNode->getAsBlock())
145 {
146 return true;
147 }
148 }
149 }
150 if ((mMask & kScalarizedVecOrMatConstructor) != 0)
151 {
152 if (node->getOp() == EOpConstruct)
153 {
154 if (node->getType().isVector() && ContainsMatrixNode(*(node->getSequence())))
155 {
156 return true;
157 }
158 else if (node->getType().isMatrix() && ContainsVectorNode(*(node->getSequence())))
159 {
160 return true;
161 }
162 }
163 }
164 return false;
165 }
166
match(TIntermTernary * node) const167 bool IntermNodePatternMatcher::match(TIntermTernary *node) const
168 {
169 if ((mMask & kUnfoldedShortCircuitExpression) != 0)
170 {
171 return true;
172 }
173 return false;
174 }
175
match(TIntermDeclaration * node) const176 bool IntermNodePatternMatcher::match(TIntermDeclaration *node) const
177 {
178 if ((mMask & kMultiDeclaration) != 0)
179 {
180 if (node->getSequence()->size() > 1)
181 {
182 return true;
183 }
184 }
185 if ((mMask & kArrayDeclaration) != 0)
186 {
187 if (node->getSequence()->front()->getAsTyped()->getType().isStructureContainingArrays())
188 {
189 return true;
190 }
191 // Need to check from all declarators whether they are arrays since that may vary between
192 // declarators.
193 for (TIntermNode *declarator : *node->getSequence())
194 {
195 if (declarator->getAsTyped()->isArray())
196 {
197 return true;
198 }
199 }
200 }
201 if ((mMask & kNamelessStructDeclaration) != 0)
202 {
203 TIntermTyped *declarator = node->getSequence()->front()->getAsTyped();
204 if (declarator->getBasicType() == EbtStruct &&
205 declarator->getType().getStruct()->symbolType() == SymbolType::Empty)
206 {
207 return true;
208 }
209 }
210 return false;
211 }
212
213 } // namespace sh
214