Edit

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

Branch :

  • Show log

    Commit

  • Author : Olli Etuaho
    Date : 2015-11-05 12:14:50
    Hash : 18b9deb4
    Message : Support writing initializers using HLSL literal syntax Instead of using constructor functions to initialize variables, it is better to use literal initializer syntax provided by HLSL when it is possible. This way shader complexity is reduced and constant array initialization doesn't have to go through as many AST transformations. Before this patch, vec4 initialization would result in the following kind of HLSL: float4 f = float4(1.0, 2.0, 3.0, 4.0); After this patch, it will be: float4 f = {1.0, 2.0, 3.0, 4.0}; Before this patch, vec2 array initialization would result in the following kind of HLSL: float2 f[2] = {0, 0, 0, 0}; angle_construct_into_2_float2(f, float2(1.0, 2.0), float2(3.0, 4.0)); After this patch, it will be: float2 f[2] = {1.0, 2.0, 3.0, 4.0}; BUG=angleproject:1094 BUG=541551 TEST=WebGL conformance tests Change-Id: I9816a8d95a2cba3964922f6b561862d478da6145 Reviewed-on: https://chromium-review.googlesource.com/311160 Reviewed-by: Zhenyao Mo <zmo@chromium.org> Tested-by: Olli Etuaho <oetuaho@nvidia.com>

  • src/compiler/translator/SeparateArrayInitialization.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 SeparateArrayInitialization function splits each array initialization into a declaration and an assignment.
    // Example:
    //     type[n] a = initializer;
    // will effectively become
    //     type[n] a;
    //     a = initializer;
    //
    // Note that if the array is declared as const, the initialization may still be split, making the
    // AST technically invalid. Because of that this transformation should only be used when subsequent
    // stages don't care about const qualifiers. However, the initialization will not be split if the
    // initializer can be written as a HLSL literal.
    
    #include "compiler/translator/SeparateArrayInitialization.h"
    
    #include "compiler/translator/IntermNode.h"
    #include "compiler/translator/OutputHLSL.h"
    
    namespace
    {
    
    class SeparateArrayInitTraverser : private TIntermTraverser
    {
      public:
        static void apply(TIntermNode *root);
      private:
        SeparateArrayInitTraverser();
        bool visitAggregate(Visit, TIntermAggregate *node) override;
    };
    
    void SeparateArrayInitTraverser::apply(TIntermNode *root)
    {
        SeparateArrayInitTraverser separateInit;
        root->traverse(&separateInit);
        separateInit.updateTree();
    }
    
    SeparateArrayInitTraverser::SeparateArrayInitTraverser()
        : TIntermTraverser(true, false, false)
    {
    }
    
    bool SeparateArrayInitTraverser::visitAggregate(Visit, TIntermAggregate *node)
    {
        if (node->getOp() == EOpDeclaration)
        {
            TIntermSequence *sequence = node->getSequence();
            TIntermBinary *initNode = sequence->back()->getAsBinaryNode();
            if (initNode != nullptr && initNode->getOp() == EOpInitialize)
            {
                TIntermTyped *initializer = initNode->getRight();
                if (initializer->isArray() && !sh::OutputHLSL::canWriteAsHLSLLiteral(initializer))
                {
                    // We rely on that array declarations have been isolated to single declarations.
                    ASSERT(sequence->size() == 1);
                    TIntermTyped *symbol = initNode->getLeft();
                    TIntermAggregate *parentAgg = getParentNode()->getAsAggregate();
                    ASSERT(parentAgg != nullptr);
    
                    TIntermSequence replacements;
    
                    TIntermAggregate *replacementDeclaration = new TIntermAggregate;
                    replacementDeclaration->setOp(EOpDeclaration);
                    replacementDeclaration->getSequence()->push_back(symbol);
                    replacementDeclaration->setLine(symbol->getLine());
                    replacements.push_back(replacementDeclaration);
    
                    TIntermBinary *replacementAssignment = new TIntermBinary(EOpAssign);
                    replacementAssignment->setLeft(symbol);
                    replacementAssignment->setRight(initializer);
                    replacementAssignment->setType(initializer->getType());
                    replacementAssignment->setLine(symbol->getLine());
                    replacements.push_back(replacementAssignment);
    
                    mMultiReplacements.push_back(NodeReplaceWithMultipleEntry(parentAgg, node, replacements));
                }
            }
            return false;
        }
        return true;
    }
    
    } // namespace
    
    void SeparateArrayInitialization(TIntermNode *root)
    {
        SeparateArrayInitTraverser::apply(root);
    }