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)68 bool IntermNodePatternMatcher::matchInternal(TIntermBinary *node, TIntermNode *parentNode)
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)90 bool IntermNodePatternMatcher::match(TIntermUnary *node)
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)102 bool IntermNodePatternMatcher::match(TIntermBinary *node, TIntermNode *parentNode)
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)111 bool IntermNodePatternMatcher::match(TIntermBinary *node,
112 TIntermNode *parentNode,
113 bool isLValueRequiredHere)
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)129 bool IntermNodePatternMatcher::match(TIntermAggregate *node, TIntermNode *parentNode)
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()) && !parentNode->getAsBlock())
142 {
143 return true;
144 }
145 }
146 }
147 if ((mMask & kScalarizedVecOrMatConstructor) != 0)
148 {
149 if (node->getOp() == EOpConstruct)
150 {
151 if (node->getType().isVector() && ContainsMatrixNode(*(node->getSequence())))
152 {
153 return true;
154 }
155 else if (node->getType().isMatrix() && ContainsVectorNode(*(node->getSequence())))
156 {
157 return true;
158 }
159 }
160 }
161 return false;
162 }
163
match(TIntermTernary * node)164 bool IntermNodePatternMatcher::match(TIntermTernary *node)
165 {
166 if ((mMask & kUnfoldedShortCircuitExpression) != 0)
167 {
168 return true;
169 }
170 return false;
171 }
172
match(TIntermDeclaration * node)173 bool IntermNodePatternMatcher::match(TIntermDeclaration *node)
174 {
175 if ((mMask & kMultiDeclaration) != 0)
176 {
177 if (node->getSequence()->size() > 1)
178 {
179 return true;
180 }
181 }
182 if ((mMask & kArrayDeclaration) != 0)
183 {
184 if (node->getSequence()->front()->getAsTyped()->getType().isStructureContainingArrays())
185 {
186 return true;
187 }
188 // Need to check from all declarators whether they are arrays since that may vary between
189 // declarators.
190 for (TIntermNode *declarator : *node->getSequence())
191 {
192 if (declarator->getAsTyped()->isArray())
193 {
194 return true;
195 }
196 }
197 }
198 if ((mMask & kNamelessStructDeclaration) != 0)
199 {
200 TIntermTyped *declarator = node->getSequence()->front()->getAsTyped();
201 if (declarator->getBasicType() == EbtStruct &&
202 declarator->getType().getStruct()->symbolType() == SymbolType::Empty)
203 {
204 return true;
205 }
206 }
207 return false;
208 }
209
210 } // namespace sh
211