Edit

kc3-lang/angle/src/compiler/translator/tree_ops/d3d/WrapSwitchStatementsInBlocks.cpp

Branch :

  • Show log

    Commit

  • Author : Shahbaz Youssefi
    Date : 2021-01-19 12:48:15
    Hash : 9f4b159b
    Message : Translator: Avoid vector copies with multi-replacement Turns push_backs into emplace_backs and changes the TIntermSequence constructor argument to &&. Bug: angleproject:5535 Change-Id: I640ce879b6ade48a28dea6385ebb7a95cb8304ff Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2636680 Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: Jamie Madill <jmadill@chromium.org> Reviewed-by: Tim Van Patten <timvp@google.com>

  • src/compiler/translator/tree_ops/d3d/WrapSwitchStatementsInBlocks.cpp
  • //
    // Copyright 2017 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.
    //
    // WrapSwitchStatementsInBlocks.cpp: Wrap switch statements in blocks and declare all switch-scoped
    // variables there to make the AST compatible with HLSL output.
    //
    // switch (init)
    // {
    //     case 0:
    //         float f;
    //     default:
    //         f = 1.0;
    // }
    //
    // becomes
    //
    // {
    //     float f;
    //     switch (init)
    //     {
    //         case 0:
    //         default:
    //             f = 1.0;
    //     }
    // }
    
    #include "compiler/translator/tree_ops/d3d/WrapSwitchStatementsInBlocks.h"
    
    #include "compiler/translator/IntermNode.h"
    #include "compiler/translator/tree_util/IntermTraverse.h"
    
    namespace sh
    {
    
    namespace
    {
    
    class WrapSwitchStatementsInBlocksTraverser : public TIntermTraverser
    {
      public:
        WrapSwitchStatementsInBlocksTraverser() : TIntermTraverser(true, false, false) {}
    
        bool visitSwitch(Visit visit, TIntermSwitch *node) override;
    };
    
    bool WrapSwitchStatementsInBlocksTraverser::visitSwitch(Visit, TIntermSwitch *node)
    {
        std::vector<TIntermDeclaration *> declarations;
        TIntermSequence *statementList = node->getStatementList()->getSequence();
        for (TIntermNode *statement : *statementList)
        {
            TIntermDeclaration *asDeclaration = statement->getAsDeclarationNode();
            if (asDeclaration)
            {
                declarations.push_back(asDeclaration);
            }
        }
        if (declarations.empty())
        {
            // We don't need to wrap the switch if it doesn't contain declarations as its direct
            // descendants.
            return true;
        }
    
        TIntermBlock *wrapperBlock = new TIntermBlock();
        for (TIntermDeclaration *declaration : declarations)
        {
            // SeparateDeclarations should have already been run.
            ASSERT(declaration->getSequence()->size() == 1);
    
            TIntermDeclaration *declarationInBlock = new TIntermDeclaration();
            TIntermSymbol *declaratorAsSymbol = declaration->getSequence()->at(0)->getAsSymbolNode();
            if (declaratorAsSymbol)
            {
                // This is a simple declaration like: "float f;"
                // Remove the declaration from inside the switch and put it in the wrapping block.
                TIntermSequence emptyReplacement;
                mMultiReplacements.emplace_back(node->getStatementList(), declaration,
                                                std::move(emptyReplacement));
    
                declarationInBlock->appendDeclarator(declaratorAsSymbol->deepCopy());
                // The declaration can't be the last statement inside the switch since unused variables
                // should already have been pruned.
                ASSERT(declaration != statementList->back());
            }
            else
            {
                // This is an init declaration like: "float f = 0.0;"
                // Change the init declaration inside the switch into an assignment and put a plain
                // declaration in the wrapping block.
                TIntermBinary *declaratorAsBinary =
                    declaration->getSequence()->at(0)->getAsBinaryNode();
                ASSERT(declaratorAsBinary);
    
                TIntermBinary *initAssignment = new TIntermBinary(
                    EOpAssign, declaratorAsBinary->getLeft(), declaratorAsBinary->getRight());
    
                queueReplacementWithParent(node->getStatementList(), declaration, initAssignment,
                                           OriginalNode::IS_DROPPED);
    
                declarationInBlock->appendDeclarator(declaratorAsBinary->getLeft()->deepCopy());
            }
            wrapperBlock->appendStatement(declarationInBlock);
        }
    
        wrapperBlock->appendStatement(node);
        queueReplacement(wrapperBlock, OriginalNode::BECOMES_CHILD);
    
        // Should be fine to process multiple switch statements, even nesting ones in the same
        // traversal.
        return true;
    }
    
    }  // anonymous namespace
    
    // Wrap switch statements in the AST into blocks when needed.
    bool WrapSwitchStatementsInBlocks(TCompiler *compiler, TIntermBlock *root)
    {
        WrapSwitchStatementsInBlocksTraverser traverser;
        root->traverse(&traverser);
        return traverser.updateTree(compiler, root);
    }
    
    }  // namespace sh