xref: /aosp_15_r20/external/angle/src/compiler/translator/tree_util/IntermNodePatternMatcher.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
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