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
IntermNodePatternMatcher(const unsigned int mask)20 IntermNodePatternMatcher::IntermNodePatternMatcher(const unsigned int mask) : mMask(mask) {}
21
22 // static
IsDynamicIndexingOfNonSSBOVectorOrMatrix(TIntermBinary * node)23 bool IntermNodePatternMatcher::IsDynamicIndexingOfNonSSBOVectorOrMatrix(TIntermBinary *node)
24 {
25 return IsDynamicIndexingOfVectorOrMatrix(node) && !IsInShaderStorageBlock(node->getLeft());
26 }
27
28 // static
IsDynamicIndexingOfVectorOrMatrix(TIntermBinary * node)29 bool IntermNodePatternMatcher::IsDynamicIndexingOfVectorOrMatrix(TIntermBinary *node)
30 {
31 return node->getOp() == EOpIndexIndirect && !node->getLeft()->isArray() &&
32 node->getLeft()->getBasicType() != EbtStruct;
33 }
34
35 // static
IsDynamicIndexingOfSwizzledVector(TIntermBinary * node)36 bool IntermNodePatternMatcher::IsDynamicIndexingOfSwizzledVector(TIntermBinary *node)
37 {
38 return IsDynamicIndexingOfVectorOrMatrix(node) && node->getLeft()->getAsSwizzleNode();
39 }
40
matchInternal(TIntermBinary * node,TIntermNode * parentNode) const41 bool IntermNodePatternMatcher::matchInternal(TIntermBinary *node, TIntermNode *parentNode) const
42 {
43 if ((mMask & kExpressionReturningArray) != 0)
44 {
45 if (node->isArray() && node->getOp() == EOpAssign && parentNode != nullptr &&
46 !parentNode->getAsBlock())
47 {
48 return true;
49 }
50 }
51
52 if ((mMask & kUnfoldedShortCircuitExpression) != 0)
53 {
54 if (node->getRight()->hasSideEffects() &&
55 (node->getOp() == EOpLogicalOr || node->getOp() == EOpLogicalAnd))
56 {
57 return true;
58 }
59 }
60 return false;
61 }
62
match(TIntermUnary * node) const63 bool IntermNodePatternMatcher::match(TIntermUnary *node) const
64 {
65 if ((mMask & kArrayLengthMethod) != 0)
66 {
67 if (node->getOp() == EOpArrayLength)
68 {
69 return true;
70 }
71 }
72 return false;
73 }
74
match(TIntermBinary * node,TIntermNode * parentNode) const75 bool IntermNodePatternMatcher::match(TIntermBinary *node, TIntermNode *parentNode) const
76 {
77 // L-value tracking information is needed to check for dynamic indexing in L-value.
78 // Traversers that don't track l-values can still use this class and match binary nodes with
79 // this variation of this method if they don't need to check for dynamic indexing in l-values.
80 ASSERT((mMask & kDynamicIndexingOfVectorOrMatrixInLValue) == 0);
81 return matchInternal(node, parentNode);
82 }
83
match(TIntermBinary * node,TIntermNode * parentNode,bool isLValueRequiredHere) const84 bool IntermNodePatternMatcher::match(TIntermBinary *node,
85 TIntermNode *parentNode,
86 bool isLValueRequiredHere) const
87 {
88 if (matchInternal(node, parentNode))
89 {
90 return true;
91 }
92 if ((mMask & kDynamicIndexingOfVectorOrMatrixInLValue) != 0)
93 {
94 if (isLValueRequiredHere && IsDynamicIndexingOfVectorOrMatrix(node))
95 {
96 return true;
97 }
98 }
99 return false;
100 }
101
match(TIntermAggregate * node,TIntermNode * parentNode) const102 bool IntermNodePatternMatcher::match(TIntermAggregate *node, TIntermNode *parentNode) const
103 {
104 if ((mMask & kExpressionReturningArray) != 0)
105 {
106 if (parentNode != nullptr)
107 {
108 TIntermBinary *parentBinary = parentNode->getAsBinaryNode();
109 bool parentIsAssignment =
110 (parentBinary != nullptr &&
111 (parentBinary->getOp() == EOpAssign || parentBinary->getOp() == EOpInitialize));
112
113 if (node->getType().isArray() && !parentIsAssignment &&
114 (node->isConstructor() || node->isFunctionCall() ||
115 (BuiltInGroup::IsBuiltIn(node->getOp()) &&
116 !BuiltInGroup::IsMath(node->getOp()))) &&
117 !parentNode->getAsBlock())
118 {
119 return true;
120 }
121 }
122 }
123 return false;
124 }
125
match(TIntermTernary * node) const126 bool IntermNodePatternMatcher::match(TIntermTernary *node) const
127 {
128 if ((mMask & kUnfoldedShortCircuitExpression) != 0)
129 {
130 return true;
131 }
132 return false;
133 }
134
match(TIntermDeclaration * node) const135 bool IntermNodePatternMatcher::match(TIntermDeclaration *node) const
136 {
137 if ((mMask & kMultiDeclaration) != 0)
138 {
139 if (node->getSequence()->size() > 1)
140 {
141 return true;
142 }
143 }
144 if ((mMask & kArrayDeclaration) != 0)
145 {
146 if (node->getSequence()->front()->getAsTyped()->getType().isStructureContainingArrays())
147 {
148 return true;
149 }
150 // Need to check from all declarators whether they are arrays since that may vary between
151 // declarators.
152 for (TIntermNode *declarator : *node->getSequence())
153 {
154 if (declarator->getAsTyped()->isArray())
155 {
156 return true;
157 }
158 }
159 }
160 if ((mMask & kNamelessStructDeclaration) != 0)
161 {
162 TIntermTyped *declarator = node->getSequence()->front()->getAsTyped();
163 if (declarator->getBasicType() == EbtStruct &&
164 declarator->getType().getStruct()->symbolType() == SymbolType::Empty)
165 {
166 return true;
167 }
168 }
169 return false;
170 }
171
172 } // namespace sh
173