tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

WrapSwitchStatementsInBlocks.cpp (4215B)


      1 //
      2 // Copyright 2017 The ANGLE Project Authors. All rights reserved.
      3 // Use of this source code is governed by a BSD-style license that can be
      4 // found in the LICENSE file.
      5 //
      6 // WrapSwitchStatementsInBlocks.cpp: Wrap switch statements in blocks and declare all switch-scoped
      7 // variables there to make the AST compatible with HLSL output.
      8 //
      9 // switch (init)
     10 // {
     11 //     case 0:
     12 //         float f;
     13 //     default:
     14 //         f = 1.0;
     15 // }
     16 //
     17 // becomes
     18 //
     19 // {
     20 //     float f;
     21 //     switch (init)
     22 //     {
     23 //         case 0:
     24 //         default:
     25 //             f = 1.0;
     26 //     }
     27 // }
     28 
     29 #include "compiler/translator/tree_ops/d3d/WrapSwitchStatementsInBlocks.h"
     30 
     31 #include "compiler/translator/IntermNode.h"
     32 #include "compiler/translator/tree_util/IntermTraverse.h"
     33 
     34 namespace sh
     35 {
     36 
     37 namespace
     38 {
     39 
     40 class WrapSwitchStatementsInBlocksTraverser : public TIntermTraverser
     41 {
     42  public:
     43    WrapSwitchStatementsInBlocksTraverser() : TIntermTraverser(true, false, false) {}
     44 
     45    bool visitSwitch(Visit visit, TIntermSwitch *node) override;
     46 };
     47 
     48 bool WrapSwitchStatementsInBlocksTraverser::visitSwitch(Visit, TIntermSwitch *node)
     49 {
     50    std::vector<TIntermDeclaration *> declarations;
     51    TIntermSequence *statementList = node->getStatementList()->getSequence();
     52    for (TIntermNode *statement : *statementList)
     53    {
     54        TIntermDeclaration *asDeclaration = statement->getAsDeclarationNode();
     55        if (asDeclaration)
     56        {
     57            declarations.push_back(asDeclaration);
     58        }
     59    }
     60    if (declarations.empty())
     61    {
     62        // We don't need to wrap the switch if it doesn't contain declarations as its direct
     63        // descendants.
     64        return true;
     65    }
     66 
     67    TIntermBlock *wrapperBlock = new TIntermBlock();
     68    for (TIntermDeclaration *declaration : declarations)
     69    {
     70        // SeparateDeclarations should have already been run.
     71        ASSERT(declaration->getSequence()->size() == 1);
     72 
     73        TIntermDeclaration *declarationInBlock = new TIntermDeclaration();
     74        TIntermSymbol *declaratorAsSymbol = declaration->getSequence()->at(0)->getAsSymbolNode();
     75        if (declaratorAsSymbol)
     76        {
     77            // This is a simple declaration like: "float f;"
     78            // Remove the declaration from inside the switch and put it in the wrapping block.
     79            TIntermSequence emptyReplacement;
     80            mMultiReplacements.emplace_back(node->getStatementList(), declaration,
     81                                            std::move(emptyReplacement));
     82 
     83            declarationInBlock->appendDeclarator(declaratorAsSymbol->deepCopy());
     84            // The declaration can't be the last statement inside the switch since unused variables
     85            // should already have been pruned.
     86            ASSERT(declaration != statementList->back());
     87        }
     88        else
     89        {
     90            // This is an init declaration like: "float f = 0.0;"
     91            // Change the init declaration inside the switch into an assignment and put a plain
     92            // declaration in the wrapping block.
     93            TIntermBinary *declaratorAsBinary =
     94                declaration->getSequence()->at(0)->getAsBinaryNode();
     95            ASSERT(declaratorAsBinary);
     96 
     97            TIntermBinary *initAssignment = new TIntermBinary(
     98                EOpAssign, declaratorAsBinary->getLeft(), declaratorAsBinary->getRight());
     99 
    100            queueReplacementWithParent(node->getStatementList(), declaration, initAssignment,
    101                                       OriginalNode::IS_DROPPED);
    102 
    103            declarationInBlock->appendDeclarator(declaratorAsBinary->getLeft()->deepCopy());
    104        }
    105        wrapperBlock->appendStatement(declarationInBlock);
    106    }
    107 
    108    wrapperBlock->appendStatement(node);
    109    queueReplacement(wrapperBlock, OriginalNode::BECOMES_CHILD);
    110 
    111    // Should be fine to process multiple switch statements, even nesting ones in the same
    112    // traversal.
    113    return true;
    114 }
    115 
    116 }  // anonymous namespace
    117 
    118 // Wrap switch statements in the AST into blocks when needed.
    119 bool WrapSwitchStatementsInBlocks(TCompiler *compiler, TIntermBlock *root)
    120 {
    121    WrapSwitchStatementsInBlocksTraverser traverser;
    122    root->traverse(&traverser);
    123    return traverser.updateTree(compiler, root);
    124 }
    125 
    126 }  // namespace sh