Line data Source code
1 : //
2 : // Copyright (c) 2002-2015 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 :
7 : #include "compiler/translator/RemoveSwitchFallThrough.h"
8 :
9 : namespace sh
10 : {
11 :
12 0 : TIntermBlock *RemoveSwitchFallThrough::removeFallThrough(TIntermBlock *statementList)
13 : {
14 0 : RemoveSwitchFallThrough rm(statementList);
15 0 : ASSERT(statementList);
16 0 : statementList->traverse(&rm);
17 0 : bool lastStatementWasBreak = rm.mLastStatementWasBreak;
18 0 : rm.mLastStatementWasBreak = true;
19 0 : rm.handlePreviousCase();
20 0 : if (!lastStatementWasBreak)
21 : {
22 0 : TIntermBranch *finalBreak = new TIntermBranch(EOpBreak, nullptr);
23 0 : rm.mStatementListOut->getSequence()->push_back(finalBreak);
24 : }
25 0 : return rm.mStatementListOut;
26 : }
27 :
28 0 : RemoveSwitchFallThrough::RemoveSwitchFallThrough(TIntermBlock *statementList)
29 : : TIntermTraverser(true, false, false),
30 : mStatementList(statementList),
31 : mLastStatementWasBreak(false),
32 0 : mPreviousCase(nullptr)
33 : {
34 0 : mStatementListOut = new TIntermBlock();
35 0 : }
36 :
37 0 : void RemoveSwitchFallThrough::visitSymbol(TIntermSymbol *node)
38 : {
39 : // Note that this assumes that switch statements which don't begin by a case statement
40 : // have already been weeded out in validation.
41 0 : mPreviousCase->getSequence()->push_back(node);
42 0 : mLastStatementWasBreak = false;
43 0 : }
44 :
45 0 : void RemoveSwitchFallThrough::visitConstantUnion(TIntermConstantUnion *node)
46 : {
47 : // Conditions of case labels are not traversed, so this is some other constant
48 : // Could be just a statement like "0;"
49 0 : mPreviousCase->getSequence()->push_back(node);
50 0 : mLastStatementWasBreak = false;
51 0 : }
52 :
53 0 : bool RemoveSwitchFallThrough::visitBinary(Visit, TIntermBinary *node)
54 : {
55 0 : mPreviousCase->getSequence()->push_back(node);
56 0 : mLastStatementWasBreak = false;
57 0 : return false;
58 : }
59 :
60 0 : bool RemoveSwitchFallThrough::visitUnary(Visit, TIntermUnary *node)
61 : {
62 0 : mPreviousCase->getSequence()->push_back(node);
63 0 : mLastStatementWasBreak = false;
64 0 : return false;
65 : }
66 :
67 0 : bool RemoveSwitchFallThrough::visitTernary(Visit, TIntermTernary *node)
68 : {
69 0 : mPreviousCase->getSequence()->push_back(node);
70 0 : mLastStatementWasBreak = false;
71 0 : return false;
72 : }
73 :
74 0 : bool RemoveSwitchFallThrough::visitIfElse(Visit, TIntermIfElse *node)
75 : {
76 0 : mPreviousCase->getSequence()->push_back(node);
77 0 : mLastStatementWasBreak = false;
78 0 : return false;
79 : }
80 :
81 0 : bool RemoveSwitchFallThrough::visitSwitch(Visit, TIntermSwitch *node)
82 : {
83 0 : mPreviousCase->getSequence()->push_back(node);
84 0 : mLastStatementWasBreak = false;
85 : // Don't go into nested switch statements
86 0 : return false;
87 : }
88 :
89 0 : void RemoveSwitchFallThrough::outputSequence(TIntermSequence *sequence, size_t startIndex)
90 : {
91 0 : for (size_t i = startIndex; i < sequence->size(); ++i)
92 : {
93 0 : mStatementListOut->getSequence()->push_back(sequence->at(i));
94 : }
95 0 : }
96 :
97 0 : void RemoveSwitchFallThrough::handlePreviousCase()
98 : {
99 0 : if (mPreviousCase)
100 0 : mCasesSharingBreak.push_back(mPreviousCase);
101 0 : if (mLastStatementWasBreak)
102 : {
103 0 : bool labelsWithNoStatements = true;
104 0 : for (size_t i = 0; i < mCasesSharingBreak.size(); ++i)
105 : {
106 0 : if (mCasesSharingBreak.at(i)->getSequence()->size() > 1)
107 : {
108 0 : labelsWithNoStatements = false;
109 : }
110 0 : if (labelsWithNoStatements)
111 : {
112 : // Fall-through is allowed in case the label has no statements.
113 0 : outputSequence(mCasesSharingBreak.at(i)->getSequence(), 0);
114 : }
115 : else
116 : {
117 : // Include all the statements that this case can fall through under the same label.
118 0 : for (size_t j = i; j < mCasesSharingBreak.size(); ++j)
119 : {
120 0 : size_t startIndex = j > i ? 1 : 0; // Add the label only from the first sequence.
121 0 : outputSequence(mCasesSharingBreak.at(j)->getSequence(), startIndex);
122 :
123 : }
124 : }
125 : }
126 0 : mCasesSharingBreak.clear();
127 : }
128 0 : mLastStatementWasBreak = false;
129 0 : mPreviousCase = nullptr;
130 0 : }
131 :
132 0 : bool RemoveSwitchFallThrough::visitCase(Visit, TIntermCase *node)
133 : {
134 0 : handlePreviousCase();
135 0 : mPreviousCase = new TIntermBlock();
136 0 : mPreviousCase->getSequence()->push_back(node);
137 : // Don't traverse the condition of the case statement
138 0 : return false;
139 : }
140 :
141 0 : bool RemoveSwitchFallThrough::visitAggregate(Visit, TIntermAggregate *node)
142 : {
143 0 : mPreviousCase->getSequence()->push_back(node);
144 0 : mLastStatementWasBreak = false;
145 0 : return false;
146 : }
147 :
148 0 : bool RemoveSwitchFallThrough::visitBlock(Visit, TIntermBlock *node)
149 : {
150 0 : if (node != mStatementList)
151 : {
152 0 : mPreviousCase->getSequence()->push_back(node);
153 0 : mLastStatementWasBreak = false;
154 0 : return false;
155 : }
156 0 : return true;
157 : }
158 :
159 0 : bool RemoveSwitchFallThrough::visitLoop(Visit, TIntermLoop *node)
160 : {
161 0 : mPreviousCase->getSequence()->push_back(node);
162 0 : mLastStatementWasBreak = false;
163 0 : return false;
164 : }
165 :
166 0 : bool RemoveSwitchFallThrough::visitBranch(Visit, TIntermBranch *node)
167 : {
168 0 : mPreviousCase->getSequence()->push_back(node);
169 : // TODO: Verify that accepting return or continue statements here doesn't cause problems.
170 0 : mLastStatementWasBreak = true;
171 0 : return false;
172 : }
173 :
174 : } // namespace sh
|