Edit

kc3-lang/angle/src/compiler/translator/PruneEmptyDeclarations.cpp

Branch :

  • Show log

    Commit

  • Author : Olli Etuaho
    Date : 2016-06-28 10:49:46
    Hash : 474a08c0
    Message : Remove qualifiers from empty struct declarations in output Empty struct declarations with qualifiers are rejected by NVIDIA GL driver version 367.27. For example this kind of construct that is expected to be accepted by the WebGL conformance tests is rejected: const struct a { int i; }; Since qualifiers do not carry meaning unless a struct declaration has declarators, they can be simply omitted from the translator output in this kind of cases to work around this driver issue. New unit test is added to check that pruning empty declarations works correctly. BUG=angleproject:1430 BUG=622492 TEST=WebGL conformance tests, angle_unittests Change-Id: Id83f83124ae597fcdfa15100d336c2c207d9449c Reviewed-on: https://chromium-review.googlesource.com/356362 Reviewed-by: Jamie Madill <jmadill@chromium.org> Commit-Queue: Olli Etuaho <oetuaho@nvidia.com>

  • src/compiler/translator/PruneEmptyDeclarations.cpp
  • //
    // Copyright (c) 2002-2015 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.
    //
    // The PruneEmptyDeclarations function prunes unnecessary empty declarations and declarators from the AST.
    
    #include "compiler/translator/PruneEmptyDeclarations.h"
    
    #include "compiler/translator/IntermNode.h"
    
    namespace
    {
    
    class PruneEmptyDeclarationsTraverser : private TIntermTraverser
    {
      public:
        static void apply(TIntermNode *root);
      private:
        PruneEmptyDeclarationsTraverser();
        bool visitAggregate(Visit, TIntermAggregate *node) override;
    };
    
    void PruneEmptyDeclarationsTraverser::apply(TIntermNode *root)
    {
        PruneEmptyDeclarationsTraverser prune;
        root->traverse(&prune);
        prune.updateTree();
    }
    
    PruneEmptyDeclarationsTraverser::PruneEmptyDeclarationsTraverser()
        : TIntermTraverser(true, false, false)
    {
    }
    
    bool PruneEmptyDeclarationsTraverser::visitAggregate(Visit, TIntermAggregate *node)
    {
        if (node->getOp() == EOpDeclaration)
        {
            TIntermSequence *sequence = node->getSequence();
            if (sequence->size() >= 1)
            {
                TIntermSymbol *sym = sequence->front()->getAsSymbolNode();
                // Prune declarations without a variable name, unless it's an interface block declaration.
                if (sym != nullptr && sym->getSymbol() == "" && !sym->isInterfaceBlock())
                {
                    if (sequence->size() > 1)
                    {
                        // Generate a replacement that will remove the empty declarator in the beginning of a declarator
                        // list. Example of a declaration that will be changed:
                        // float, a;
                        // will be changed to
                        // float a;
                        // This applies also to struct declarations.
                        TIntermSequence emptyReplacement;
                        mMultiReplacements.push_back(NodeReplaceWithMultipleEntry(node, sym, emptyReplacement));
                    }
                    else if (sym->getBasicType() != EbtStruct)
                    {
                        // Single struct declarations may just declare the struct type and no variables, so they should
                        // not be pruned. All other single empty declarations can be pruned entirely. Example of an empty
                        // declaration that will be pruned:
                        // float;
                        TIntermSequence emptyReplacement;
                        TIntermAggregate *parentAgg = getParentNode()->getAsAggregate();
                        ASSERT(parentAgg != nullptr);
                        mMultiReplacements.push_back(NodeReplaceWithMultipleEntry(parentAgg, node, emptyReplacement));
                    }
                    else if (sym->getType().getQualifier() != EvqGlobal &&
                             sym->getType().getQualifier() != EvqTemporary)
                    {
                        // We've hit an empty struct declaration with a qualifier, for example like
                        // this:
                        // const struct a { int i; };
                        // NVIDIA GL driver version 367.27 doesn't accept this kind of declarations, so
                        // we convert the declaration to a regular struct declaration. This is okay,
                        // since ESSL 1.00 spec section 4.1.8 says about structs that "The optional
                        // qualifiers only apply to any declarators, and are not part of the type being
                        // defined for name."
    
                        if (mInGlobalScope)
                        {
                            sym->getTypePointer()->setQualifier(EvqGlobal);
                        }
                        else
                        {
                            sym->getTypePointer()->setQualifier(EvqTemporary);
                        }
                    }
                }
            }
            return false;
        }
        return true;
    }
    
    } // namespace
    
    void PruneEmptyDeclarations(TIntermNode *root)
    {
        PruneEmptyDeclarationsTraverser::apply(root);
    }