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