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
matchInternal(TIntermBinary * node,TIntermNode * parentNode)62 bool IntermNodePatternMatcher::matchInternal(TIntermBinary *node, TIntermNode *parentNode)
63 {
64 if ((mMask & kExpressionReturningArray) != 0)
65 {
66 if (node->isArray() && node->getOp() == EOpAssign && parentNode != nullptr &&
67 !parentNode->getAsBlock())
68 {
69 return true;
70 }
71 }
72
73 if ((mMask & kUnfoldedShortCircuitExpression) != 0)
74 {
75 if (node->getRight()->hasSideEffects() &&
76 (node->getOp() == EOpLogicalOr || node->getOp() == EOpLogicalAnd))
77 {
78 return true;
79 }
80 }
81 return false;
82 }
83
match(TIntermUnary * node)84 bool IntermNodePatternMatcher::match(TIntermUnary *node)
85 {
86 if ((mMask & kArrayLengthMethod) != 0)
87 {
88 if (node->getOp() == EOpArrayLength)
89 {
90 return true;
91 }
92 }
93 return false;
94 }
95
match(TIntermBinary * node,TIntermNode * parentNode)96 bool IntermNodePatternMatcher::match(TIntermBinary *node, TIntermNode *parentNode)
97 {
98 // L-value tracking information is needed to check for dynamic indexing in L-value.
99 // Traversers that don't track l-values can still use this class and match binary nodes with
100 // this variation of this method if they don't need to check for dynamic indexing in l-values.
101 ASSERT((mMask & kDynamicIndexingOfVectorOrMatrixInLValue) == 0);
102 return matchInternal(node, parentNode);
103 }
104
match(TIntermBinary * node,TIntermNode * parentNode,bool isLValueRequiredHere)105 bool IntermNodePatternMatcher::match(TIntermBinary *node,
106 TIntermNode *parentNode,
107 bool isLValueRequiredHere)
108 {
109 if (matchInternal(node, parentNode))
110 {
111 return true;
112 }
113 if ((mMask & kDynamicIndexingOfVectorOrMatrixInLValue) != 0)
114 {
115 if (isLValueRequiredHere && IsDynamicIndexingOfVectorOrMatrix(node))
116 {
117 return true;
118 }
119 }
120 return false;
121 }
122
match(TIntermAggregate * node,TIntermNode * parentNode)123 bool IntermNodePatternMatcher::match(TIntermAggregate *node, TIntermNode *parentNode)
124 {
125 if ((mMask & kExpressionReturningArray) != 0)
126 {
127 if (parentNode != nullptr)
128 {
129 TIntermBinary *parentBinary = parentNode->getAsBinaryNode();
130 bool parentIsAssignment =
131 (parentBinary != nullptr &&
132 (parentBinary->getOp() == EOpAssign || parentBinary->getOp() == EOpInitialize));
133
134 if (node->getType().isArray() && !parentIsAssignment &&
135 (node->isConstructor() || node->isFunctionCall()) && !parentNode->getAsBlock())
136 {
137 return true;
138 }
139 }
140 }
141 if ((mMask & kScalarizedVecOrMatConstructor) != 0)
142 {
143 if (node->getOp() == EOpConstruct)
144 {
145 if (node->getType().isVector() && ContainsMatrixNode(*(node->getSequence())))
146 {
147 return true;
148 }
149 else if (node->getType().isMatrix() && ContainsVectorNode(*(node->getSequence())))
150 {
151 return true;
152 }
153 }
154 }
155 return false;
156 }
157
match(TIntermTernary * node)158 bool IntermNodePatternMatcher::match(TIntermTernary *node)
159 {
160 if ((mMask & kUnfoldedShortCircuitExpression) != 0)
161 {
162 return true;
163 }
164 return false;
165 }
166
match(TIntermDeclaration * node)167 bool IntermNodePatternMatcher::match(TIntermDeclaration *node)
168 {
169 if ((mMask & kMultiDeclaration) != 0)
170 {
171 if (node->getSequence()->size() > 1)
172 {
173 return true;
174 }
175 }
176 if ((mMask & kArrayDeclaration) != 0)
177 {
178 if (node->getSequence()->front()->getAsTyped()->getType().isStructureContainingArrays())
179 {
180 return true;
181 }
182 // Need to check from all declarators whether they are arrays since that may vary between
183 // declarators.
184 for (TIntermNode *declarator : *node->getSequence())
185 {
186 if (declarator->getAsTyped()->isArray())
187 {
188 return true;
189 }
190 }
191 }
192 if ((mMask & kNamelessStructDeclaration) != 0)
193 {
194 TIntermTyped *declarator = node->getSequence()->front()->getAsTyped();
195 if (declarator->getBasicType() == EbtStruct &&
196 declarator->getType().getStruct()->symbolType() == SymbolType::Empty)
197 {
198 return true;
199 }
200 }
201 return false;
202 }
203
204 } // namespace sh
205