summaryrefslogtreecommitdiffstats
path: root/src/3rdparty/angle/src/compiler/translator/RemoveNoOpCasesFromEndOfSwitchStatements.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/3rdparty/angle/src/compiler/translator/RemoveNoOpCasesFromEndOfSwitchStatements.cpp')
-rw-r--r--src/3rdparty/angle/src/compiler/translator/RemoveNoOpCasesFromEndOfSwitchStatements.cpp116
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