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 | // 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 | |
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 | |
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 | |
47 | IntermNodePatternMatcher::IntermNodePatternMatcher(const unsigned int mask) : mMask(mask) {} |
48 | |
49 | // static |
50 | bool IntermNodePatternMatcher::IsDynamicIndexingOfNonSSBOVectorOrMatrix(TIntermBinary *node) |
51 | { |
52 | return IsDynamicIndexingOfVectorOrMatrix(node) && !IsInShaderStorageBlock(node->getLeft()); |
53 | } |
54 | |
55 | // static |
56 | bool IntermNodePatternMatcher::IsDynamicIndexingOfVectorOrMatrix(TIntermBinary *node) |
57 | { |
58 | return node->getOp() == EOpIndexIndirect && !node->getLeft()->isArray() && |
59 | node->getLeft()->getBasicType() != EbtStruct; |
60 | } |
61 | |
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 | |
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 | |
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 | |
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 | |
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 | |
158 | bool IntermNodePatternMatcher::match(TIntermTernary *node) |
159 | { |
160 | if ((mMask & kUnfoldedShortCircuitExpression) != 0) |
161 | { |
162 | return true; |
163 | } |
164 | return false; |
165 | } |
166 | |
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 |