diff options
Diffstat (limited to 'src/3rdparty/angle/src/compiler/translator/RemoveNoOpCasesFromEndOfSwitchStatements.cpp')
-rw-r--r-- | src/3rdparty/angle/src/compiler/translator/RemoveNoOpCasesFromEndOfSwitchStatements.cpp | 116 |
1 files changed, 116 insertions, 0 deletions
diff --git a/src/3rdparty/angle/src/compiler/translator/RemoveNoOpCasesFromEndOfSwitchStatements.cpp b/src/3rdparty/angle/src/compiler/translator/RemoveNoOpCasesFromEndOfSwitchStatements.cpp new file mode 100644 index 0000000000..b86d64d7a3 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/RemoveNoOpCasesFromEndOfSwitchStatements.cpp @@ -0,0 +1,116 @@ +// +// Copyright (c) 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. +// +// RemoveNoOpCasesFromEndOfSwitchStatements.cpp: Clean up cases from the end of a switch statement +// that only contain no-ops. + +#include "compiler/translator/RemoveNoOpCasesFromEndOfSwitchStatements.h" + +#include "compiler/translator/IntermNode.h" +#include "compiler/translator/IntermNode_util.h" +#include "compiler/translator/IntermTraverse.h" +#include "compiler/translator/SymbolTable.h" + +namespace sh +{ + +namespace +{ + +bool AreEmptyBlocks(TIntermSequence *statements, size_t i); + +bool IsEmptyBlock(TIntermNode *node) +{ + TIntermBlock *asBlock = node->getAsBlock(); + if (asBlock) + { + if (asBlock->getSequence()->empty()) + { + return true; + } + return AreEmptyBlocks(asBlock->getSequence(), 0u); + } + // Empty declarations should have already been pruned, otherwise they would need to be handled + // here. Note that declarations for struct types do contain a nameless child node. + ASSERT(node->getAsDeclarationNode() == nullptr || + !node->getAsDeclarationNode()->getSequence()->empty()); + // Pure literal statements should also already be pruned. + ASSERT(node->getAsConstantUnion() == nullptr); + return false; +} + +// Return true if all statements in "statements" starting from index i consist only of empty blocks +// and no-op statements. Returns true also if there are no statements. +bool AreEmptyBlocks(TIntermSequence *statements, size_t i) +{ + for (; i < statements->size(); ++i) + { + if (!IsEmptyBlock(statements->at(i))) + { + return false; + } + } + return true; +} + +void RemoveNoOpCasesFromEndOfStatementList(TIntermBlock *statementList, TSymbolTable *symbolTable) +{ + TIntermSequence *statements = statementList->getSequence(); + + bool foundDeadCase = false; + do + { + if (statements->empty()) + { + return; + } + + // Find the last case label. + size_t i = statements->size(); + while (i > 0u && !(*statements)[i - 1]->getAsCaseNode()) + { + --i; + } + // Now i is the index of the first statement following the last label inside the switch + // statement. + ASSERT(i > 0u); + + foundDeadCase = AreEmptyBlocks(statements, i); + if (foundDeadCase) + { + statements->erase(statements->begin() + (i - 1u), statements->end()); + } + } while (foundDeadCase); +} + +class RemoveNoOpCasesFromEndOfSwitchTraverser : public TIntermTraverser +{ + public: + RemoveNoOpCasesFromEndOfSwitchTraverser(TSymbolTable *symbolTable) + : TIntermTraverser(true, false, false, symbolTable) + { + } + + bool visitSwitch(Visit visit, TIntermSwitch *node) override; +}; + +bool RemoveNoOpCasesFromEndOfSwitchTraverser::visitSwitch(Visit visit, TIntermSwitch *node) +{ + // Here we may mutate the statement list, but it's safe since traversal has not yet reached + // there. + RemoveNoOpCasesFromEndOfStatementList(node->getStatementList(), mSymbolTable); + // Handle also nested switch statements. + return true; +} + +} // anonymous namespace + +void RemoveNoOpCasesFromEndOfSwitchStatements(TIntermBlock *root, TSymbolTable *symbolTable) +{ + RemoveNoOpCasesFromEndOfSwitchTraverser traverser(symbolTable); + root->traverse(&traverser); +} + +} // namespace sh |