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