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