blob: d08c386da07fe90df6ae21982a48e111c3dc7f0e [file] [log] [blame]
//
// Copyright 2016 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// IntermNodePatternMatcher is a helper class for matching node trees to given patterns.
// It can be used whenever the same checks for certain node structures are common to multiple AST
// traversers.
//
#include "compiler/translator/tree_util/IntermNodePatternMatcher.h"
#include "compiler/translator/IntermNode.h"
#include "compiler/translator/SymbolTable.h"
#include "compiler/translator/util.h"
namespace sh
{
namespace
{
bool ContainsMatrixNode(const TIntermSequence &sequence)
{
for (size_t ii = 0; ii < sequence.size(); ++ii)
{
TIntermTyped *node = sequence[ii]->getAsTyped();
if (node && node->isMatrix())
return true;
}
return false;
}
bool ContainsVectorNode(const TIntermSequence &sequence)
{
for (size_t ii = 0; ii < sequence.size(); ++ii)
{
TIntermTyped *node = sequence[ii]->getAsTyped();
if (node && node->isVector())
return true;
}
return false;
}
} // anonymous namespace
IntermNodePatternMatcher::IntermNodePatternMatcher(const unsigned int mask) : mMask(mask) {}
// static
bool IntermNodePatternMatcher::IsDynamicIndexingOfNonSSBOVectorOrMatrix(TIntermBinary *node)
{
return IsDynamicIndexingOfVectorOrMatrix(node) && !IsInShaderStorageBlock(node->getLeft());
}
// static
bool IntermNodePatternMatcher::IsDynamicIndexingOfVectorOrMatrix(TIntermBinary *node)
{
return node->getOp() == EOpIndexIndirect && !node->getLeft()->isArray() &&
node->getLeft()->getBasicType() != EbtStruct;
}
// static
bool IntermNodePatternMatcher::IsDynamicIndexingOfSwizzledVector(TIntermBinary *node)
{
return IsDynamicIndexingOfVectorOrMatrix(node) && node->getLeft()->getAsSwizzleNode();
}
bool IntermNodePatternMatcher::matchInternal(TIntermBinary *node, TIntermNode *parentNode)
{
if ((mMask & kExpressionReturningArray) != 0)
{
if (node->isArray() && node->getOp() == EOpAssign && parentNode != nullptr &&
!parentNode->getAsBlock())
{
return true;
}
}
if ((mMask & kUnfoldedShortCircuitExpression) != 0)
{
if (node->getRight()->hasSideEffects() &&
(node->getOp() == EOpLogicalOr || node->getOp() == EOpLogicalAnd))
{
return true;
}
}
return false;
}
bool IntermNodePatternMatcher::match(TIntermUnary *node)
{
if ((mMask & kArrayLengthMethod) != 0)
{
if (node->getOp() == EOpArrayLength)
{
return true;
}
}
return false;
}
bool IntermNodePatternMatcher::match(TIntermBinary *node, TIntermNode *parentNode)
{
// L-value tracking information is needed to check for dynamic indexing in L-value.
// Traversers that don't track l-values can still use this class and match binary nodes with
// this variation of this method if they don't need to check for dynamic indexing in l-values.
ASSERT((mMask & kDynamicIndexingOfVectorOrMatrixInLValue) == 0);
return matchInternal(node, parentNode);
}
bool IntermNodePatternMatcher::match(TIntermBinary *node,
TIntermNode *parentNode,
bool isLValueRequiredHere)
{
if (matchInternal(node, parentNode))
{
return true;
}
if ((mMask & kDynamicIndexingOfVectorOrMatrixInLValue) != 0)
{
if (isLValueRequiredHere && IsDynamicIndexingOfVectorOrMatrix(node))
{
return true;
}
}
return false;
}
bool IntermNodePatternMatcher::match(TIntermAggregate *node, TIntermNode *parentNode)
{
if ((mMask & kExpressionReturningArray) != 0)
{
if (parentNode != nullptr)
{
TIntermBinary *parentBinary = parentNode->getAsBinaryNode();
bool parentIsAssignment =
(parentBinary != nullptr &&
(parentBinary->getOp() == EOpAssign || parentBinary->getOp() == EOpInitialize));
if (node->getType().isArray() && !parentIsAssignment &&
(node->isConstructor() || node->isFunctionCall()) && !parentNode->getAsBlock())
{
return true;
}
}
}
if ((mMask & kScalarizedVecOrMatConstructor) != 0)
{
if (node->getOp() == EOpConstruct)
{
if (node->getType().isVector() && ContainsMatrixNode(*(node->getSequence())))
{
return true;
}
else if (node->getType().isMatrix() && ContainsVectorNode(*(node->getSequence())))
{
return true;
}
}
}
return false;
}
bool IntermNodePatternMatcher::match(TIntermTernary *node)
{
if ((mMask & kUnfoldedShortCircuitExpression) != 0)
{
return true;
}
return false;
}
bool IntermNodePatternMatcher::match(TIntermDeclaration *node)
{
if ((mMask & kMultiDeclaration) != 0)
{
if (node->getSequence()->size() > 1)
{
return true;
}
}
if ((mMask & kArrayDeclaration) != 0)
{
if (node->getSequence()->front()->getAsTyped()->getType().isStructureContainingArrays())
{
return true;
}
// Need to check from all declarators whether they are arrays since that may vary between
// declarators.
for (TIntermNode *declarator : *node->getSequence())
{
if (declarator->getAsTyped()->isArray())
{
return true;
}
}
}
if ((mMask & kNamelessStructDeclaration) != 0)
{
TIntermTyped *declarator = node->getSequence()->front()->getAsTyped();
if (declarator->getBasicType() == EbtStruct &&
declarator->getType().getStruct()->symbolType() == SymbolType::Empty)
{
return true;
}
}
return false;
}
} // namespace sh