tor-browser

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

PruneEmptyCases.cpp (3854B)


      1 //
      2 // Copyright 2018 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 // PruneEmptyCases.cpp: The PruneEmptyCases function prunes cases that are followed by nothing from
      7 // the AST.
      8 
      9 #include "compiler/translator/tree_ops/PruneEmptyCases.h"
     10 
     11 #include "compiler/translator/Symbol.h"
     12 #include "compiler/translator/tree_util/IntermTraverse.h"
     13 
     14 namespace sh
     15 {
     16 
     17 namespace
     18 {
     19 
     20 bool AreEmptyBlocks(const TIntermSequence *statements);
     21 
     22 bool IsEmptyBlock(TIntermNode *node)
     23 {
     24    TIntermBlock *asBlock = node->getAsBlock();
     25    if (asBlock)
     26    {
     27        return AreEmptyBlocks(asBlock->getSequence());
     28    }
     29    // Empty declarations should have already been pruned, otherwise they would need to be handled
     30    // here. Note that declarations for struct types do contain a nameless child node.
     31    ASSERT(node->getAsDeclarationNode() == nullptr ||
     32           !node->getAsDeclarationNode()->getSequence()->empty());
     33    // Pure literal statements should also already be pruned.
     34    ASSERT(node->getAsConstantUnion() == nullptr);
     35    return false;
     36 }
     37 
     38 // Return true if all statements in "statements" consist only of empty blocks and no-op statements.
     39 // Returns true also if there are no statements.
     40 bool AreEmptyBlocks(const TIntermSequence *statements)
     41 {
     42    for (size_t i = 0u; i < statements->size(); ++i)
     43    {
     44        if (!IsEmptyBlock(statements->at(i)))
     45        {
     46            return false;
     47        }
     48    }
     49    return true;
     50 }
     51 
     52 class PruneEmptyCasesTraverser : private TIntermTraverser
     53 {
     54  public:
     55    [[nodiscard]] static bool apply(TCompiler *compiler, TIntermBlock *root);
     56 
     57  private:
     58    PruneEmptyCasesTraverser();
     59    bool visitSwitch(Visit visit, TIntermSwitch *node) override;
     60 };
     61 
     62 bool PruneEmptyCasesTraverser::apply(TCompiler *compiler, TIntermBlock *root)
     63 {
     64    PruneEmptyCasesTraverser prune;
     65    root->traverse(&prune);
     66    return prune.updateTree(compiler, root);
     67 }
     68 
     69 PruneEmptyCasesTraverser::PruneEmptyCasesTraverser() : TIntermTraverser(true, false, false) {}
     70 
     71 bool PruneEmptyCasesTraverser::visitSwitch(Visit visit, TIntermSwitch *node)
     72 {
     73    // This may mutate the statementList, but that's okay, since traversal has not yet reached
     74    // there.
     75    TIntermBlock *statementList = node->getStatementList();
     76    TIntermSequence *statements = statementList->getSequence();
     77 
     78    // Iterate block children in reverse order. Cases that are only followed by other cases or empty
     79    // blocks are marked for pruning.
     80    size_t i                       = statements->size();
     81    size_t lastNoOpInStatementList = i;
     82    while (i > 0)
     83    {
     84        --i;
     85        TIntermNode *statement = statements->at(i);
     86        if (statement->getAsCaseNode() || IsEmptyBlock(statement))
     87        {
     88            lastNoOpInStatementList = i;
     89        }
     90        else
     91        {
     92            break;
     93        }
     94    }
     95    if (lastNoOpInStatementList == 0)
     96    {
     97        // Remove the entire switch statement, extracting the init expression if needed.
     98        TIntermTyped *init = node->getInit();
     99        if (init->hasSideEffects())
    100        {
    101            queueReplacement(init, OriginalNode::IS_DROPPED);
    102        }
    103        else
    104        {
    105            TIntermSequence emptyReplacement;
    106            ASSERT(getParentNode()->getAsBlock());
    107            mMultiReplacements.emplace_back(getParentNode()->getAsBlock(), node,
    108                                            std::move(emptyReplacement));
    109        }
    110        return false;
    111    }
    112    if (lastNoOpInStatementList < statements->size())
    113    {
    114        statements->erase(statements->begin() + lastNoOpInStatementList, statements->end());
    115    }
    116 
    117    return true;
    118 }
    119 
    120 }  // namespace
    121 
    122 bool PruneEmptyCases(TCompiler *compiler, TIntermBlock *root)
    123 {
    124    return PruneEmptyCasesTraverser::apply(compiler, root);
    125 }
    126 
    127 }  // namespace sh