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