summaryrefslogtreecommitdiffstats
path: root/gfx/angle/src/compiler/translator/RemoveSwitchFallThrough.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/angle/src/compiler/translator/RemoveSwitchFallThrough.cpp')
-rwxr-xr-xgfx/angle/src/compiler/translator/RemoveSwitchFallThrough.cpp174
1 files changed, 174 insertions, 0 deletions
diff --git a/gfx/angle/src/compiler/translator/RemoveSwitchFallThrough.cpp b/gfx/angle/src/compiler/translator/RemoveSwitchFallThrough.cpp
new file mode 100755
index 000000000..dd995af47
--- /dev/null
+++ b/gfx/angle/src/compiler/translator/RemoveSwitchFallThrough.cpp
@@ -0,0 +1,174 @@
+//
+// Copyright (c) 2002-2015 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.
+//
+
+#include "compiler/translator/RemoveSwitchFallThrough.h"
+
+namespace sh
+{
+
+TIntermBlock *RemoveSwitchFallThrough::removeFallThrough(TIntermBlock *statementList)
+{
+ RemoveSwitchFallThrough rm(statementList);
+ ASSERT(statementList);
+ statementList->traverse(&rm);
+ bool lastStatementWasBreak = rm.mLastStatementWasBreak;
+ rm.mLastStatementWasBreak = true;
+ rm.handlePreviousCase();
+ if (!lastStatementWasBreak)
+ {
+ TIntermBranch *finalBreak = new TIntermBranch(EOpBreak, nullptr);
+ rm.mStatementListOut->getSequence()->push_back(finalBreak);
+ }
+ return rm.mStatementListOut;
+}
+
+RemoveSwitchFallThrough::RemoveSwitchFallThrough(TIntermBlock *statementList)
+ : TIntermTraverser(true, false, false),
+ mStatementList(statementList),
+ mLastStatementWasBreak(false),
+ mPreviousCase(nullptr)
+{
+ mStatementListOut = new TIntermBlock();
+}
+
+void RemoveSwitchFallThrough::visitSymbol(TIntermSymbol *node)
+{
+ // Note that this assumes that switch statements which don't begin by a case statement
+ // have already been weeded out in validation.
+ mPreviousCase->getSequence()->push_back(node);
+ mLastStatementWasBreak = false;
+}
+
+void RemoveSwitchFallThrough::visitConstantUnion(TIntermConstantUnion *node)
+{
+ // Conditions of case labels are not traversed, so this is some other constant
+ // Could be just a statement like "0;"
+ mPreviousCase->getSequence()->push_back(node);
+ mLastStatementWasBreak = false;
+}
+
+bool RemoveSwitchFallThrough::visitBinary(Visit, TIntermBinary *node)
+{
+ mPreviousCase->getSequence()->push_back(node);
+ mLastStatementWasBreak = false;
+ return false;
+}
+
+bool RemoveSwitchFallThrough::visitUnary(Visit, TIntermUnary *node)
+{
+ mPreviousCase->getSequence()->push_back(node);
+ mLastStatementWasBreak = false;
+ return false;
+}
+
+bool RemoveSwitchFallThrough::visitTernary(Visit, TIntermTernary *node)
+{
+ mPreviousCase->getSequence()->push_back(node);
+ mLastStatementWasBreak = false;
+ return false;
+}
+
+bool RemoveSwitchFallThrough::visitIfElse(Visit, TIntermIfElse *node)
+{
+ mPreviousCase->getSequence()->push_back(node);
+ mLastStatementWasBreak = false;
+ return false;
+}
+
+bool RemoveSwitchFallThrough::visitSwitch(Visit, TIntermSwitch *node)
+{
+ mPreviousCase->getSequence()->push_back(node);
+ mLastStatementWasBreak = false;
+ // Don't go into nested switch statements
+ return false;
+}
+
+void RemoveSwitchFallThrough::outputSequence(TIntermSequence *sequence, size_t startIndex)
+{
+ for (size_t i = startIndex; i < sequence->size(); ++i)
+ {
+ mStatementListOut->getSequence()->push_back(sequence->at(i));
+ }
+}
+
+void RemoveSwitchFallThrough::handlePreviousCase()
+{
+ if (mPreviousCase)
+ mCasesSharingBreak.push_back(mPreviousCase);
+ if (mLastStatementWasBreak)
+ {
+ bool labelsWithNoStatements = true;
+ for (size_t i = 0; i < mCasesSharingBreak.size(); ++i)
+ {
+ if (mCasesSharingBreak.at(i)->getSequence()->size() > 1)
+ {
+ labelsWithNoStatements = false;
+ }
+ if (labelsWithNoStatements)
+ {
+ // Fall-through is allowed in case the label has no statements.
+ outputSequence(mCasesSharingBreak.at(i)->getSequence(), 0);
+ }
+ else
+ {
+ // Include all the statements that this case can fall through under the same label.
+ for (size_t j = i; j < mCasesSharingBreak.size(); ++j)
+ {
+ size_t startIndex = j > i ? 1 : 0; // Add the label only from the first sequence.
+ outputSequence(mCasesSharingBreak.at(j)->getSequence(), startIndex);
+
+ }
+ }
+ }
+ mCasesSharingBreak.clear();
+ }
+ mLastStatementWasBreak = false;
+ mPreviousCase = nullptr;
+}
+
+bool RemoveSwitchFallThrough::visitCase(Visit, TIntermCase *node)
+{
+ handlePreviousCase();
+ mPreviousCase = new TIntermBlock();
+ mPreviousCase->getSequence()->push_back(node);
+ // Don't traverse the condition of the case statement
+ return false;
+}
+
+bool RemoveSwitchFallThrough::visitAggregate(Visit, TIntermAggregate *node)
+{
+ mPreviousCase->getSequence()->push_back(node);
+ mLastStatementWasBreak = false;
+ return false;
+}
+
+bool RemoveSwitchFallThrough::visitBlock(Visit, TIntermBlock *node)
+{
+ if (node != mStatementList)
+ {
+ mPreviousCase->getSequence()->push_back(node);
+ mLastStatementWasBreak = false;
+ return false;
+ }
+ return true;
+}
+
+bool RemoveSwitchFallThrough::visitLoop(Visit, TIntermLoop *node)
+{
+ mPreviousCase->getSequence()->push_back(node);
+ mLastStatementWasBreak = false;
+ return false;
+}
+
+bool RemoveSwitchFallThrough::visitBranch(Visit, TIntermBranch *node)
+{
+ mPreviousCase->getSequence()->push_back(node);
+ // TODO: Verify that accepting return or continue statements here doesn't cause problems.
+ mLastStatementWasBreak = true;
+ return false;
+}
+
+} // namespace sh