Edit

kc3-lang/angle/src/compiler/translator/tree_util/IntermNodePatternMatcher.cpp

Branch :

  • Show log

    Commit

  • Author : jchen10
    Date : 2019-10-18 16:01:34
    Hash : b3070102
    Message : Add SH_REMOVE_DYNAMIC_INDEXING_OF_SWIZZLED_VECTOR This is a workaround for the webgl2 conformance test case WebglConformance_conformance2_glsl3_vector_dynamic_indexing_swizzled_lvalue. Dynamic indexing of swizzled lvalue like "v.zyx[i] = 0.0" is problematic on various platforms. This removes the indexing by translating it this way: void dyn_index_write_vec3(inout vec3 base, in int index, in float value){ switch (index) { case (0): (base[0] = value); return ; case (1): (base[1] = value); return ; case (2): (base[2] = value); return ; default: break; } if ((index < 0)) { (base[0] = value); return ; } { (base[2] = value); } } ... dyn_index_write_vec3(v.zyx, i, 0.0); ... Bug: chromium:709351 Change-Id: I971b38eb404209b56e6764af1063878c078a7e88 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1869109 Commit-Queue: Jie A Chen <jie.a.chen@intel.com> Reviewed-by: Geoff Lang <geofflang@chromium.org>

  • src/compiler/translator/tree_util/IntermNodePatternMatcher.cpp
  • //
    // 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