IntermNodePatternMatcher.cpp (6229B)
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 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 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 47 IntermNodePatternMatcher::IntermNodePatternMatcher(const unsigned int mask) : mMask(mask) {} 48 49 // static 50 bool IntermNodePatternMatcher::IsDynamicIndexingOfNonSSBOVectorOrMatrix(TIntermBinary *node) 51 { 52 return IsDynamicIndexingOfVectorOrMatrix(node) && !IsInShaderStorageBlock(node->getLeft()); 53 } 54 55 // static 56 bool IntermNodePatternMatcher::IsDynamicIndexingOfVectorOrMatrix(TIntermBinary *node) 57 { 58 return node->getOp() == EOpIndexIndirect && !node->getLeft()->isArray() && 59 node->getLeft()->getBasicType() != EbtStruct; 60 } 61 62 // static 63 bool IntermNodePatternMatcher::IsDynamicIndexingOfSwizzledVector(TIntermBinary *node) 64 { 65 return IsDynamicIndexingOfVectorOrMatrix(node) && node->getLeft()->getAsSwizzleNode(); 66 } 67 68 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 90 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 102 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 111 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 129 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 167 bool IntermNodePatternMatcher::match(TIntermTernary *node) const 168 { 169 if ((mMask & kUnfoldedShortCircuitExpression) != 0) 170 { 171 return true; 172 } 173 return false; 174 } 175 176 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