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