blob: 8a4a0be4032efeafc8fca1918e6cbdf9dfe2167b [file] [log] [blame]
Olli Etuaho2cd7a0e2015-02-27 13:57:32 +02001//
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//
Olli Etuahoaf5070f2017-10-10 13:53:25 +03006// RemoveSwitchFallThrough.cpp: Remove fall-through from switch statements.
7// Note that it is unsafe to do further AST transformations on the AST generated
8// by this function. It leaves duplicate nodes in the AST making replacements
9// unreliable.
Olli Etuaho2cd7a0e2015-02-27 13:57:32 +020010
11#include "compiler/translator/RemoveSwitchFallThrough.h"
12
Olli Etuahoaf5070f2017-10-10 13:53:25 +030013#include "compiler/translator/IntermTraverse.h"
14
Jamie Madill45bcc782016-11-07 13:58:48 -050015namespace sh
16{
17
Olli Etuahoaf5070f2017-10-10 13:53:25 +030018namespace
Olli Etuaho2cd7a0e2015-02-27 13:57:32 +020019{
Olli Etuahoaf5070f2017-10-10 13:53:25 +030020
21class RemoveSwitchFallThroughTraverser : public TIntermTraverser
22{
23 public:
24 static TIntermBlock *removeFallThrough(TIntermBlock *statementList);
25
26 private:
27 RemoveSwitchFallThroughTraverser(TIntermBlock *statementList);
28
29 void visitSymbol(TIntermSymbol *node) override;
30 void visitConstantUnion(TIntermConstantUnion *node) override;
Olli Etuaho78507c62017-10-10 15:06:45 +030031 bool visitDeclaration(Visit, TIntermDeclaration *node) override;
Olli Etuahoaf5070f2017-10-10 13:53:25 +030032 bool visitBinary(Visit, TIntermBinary *node) override;
33 bool visitUnary(Visit, TIntermUnary *node) override;
34 bool visitTernary(Visit visit, TIntermTernary *node) override;
Olli Etuaho78507c62017-10-10 15:06:45 +030035 bool visitSwizzle(Visit, TIntermSwizzle *node) override;
Olli Etuahoaf5070f2017-10-10 13:53:25 +030036 bool visitIfElse(Visit visit, TIntermIfElse *node) override;
37 bool visitSwitch(Visit, TIntermSwitch *node) override;
38 bool visitCase(Visit, TIntermCase *node) override;
39 bool visitAggregate(Visit, TIntermAggregate *node) override;
40 bool visitBlock(Visit, TIntermBlock *node) override;
41 bool visitLoop(Visit, TIntermLoop *node) override;
42 bool visitBranch(Visit, TIntermBranch *node) override;
43
44 void outputSequence(TIntermSequence *sequence, size_t startIndex);
45 void handlePreviousCase();
46
47 TIntermBlock *mStatementList;
48 TIntermBlock *mStatementListOut;
49 bool mLastStatementWasBreak;
50 TIntermBlock *mPreviousCase;
51 std::vector<TIntermBlock *> mCasesSharingBreak;
52};
53
54TIntermBlock *RemoveSwitchFallThroughTraverser::removeFallThrough(TIntermBlock *statementList)
55{
56 RemoveSwitchFallThroughTraverser rm(statementList);
Olli Etuaho2cd7a0e2015-02-27 13:57:32 +020057 ASSERT(statementList);
58 statementList->traverse(&rm);
59 bool lastStatementWasBreak = rm.mLastStatementWasBreak;
Jamie Madilld7b1ab52016-12-12 14:42:19 -050060 rm.mLastStatementWasBreak = true;
Olli Etuaho2cd7a0e2015-02-27 13:57:32 +020061 rm.handlePreviousCase();
62 if (!lastStatementWasBreak)
63 {
64 TIntermBranch *finalBreak = new TIntermBranch(EOpBreak, nullptr);
65 rm.mStatementListOut->getSequence()->push_back(finalBreak);
66 }
67 return rm.mStatementListOut;
68}
69
Olli Etuahoaf5070f2017-10-10 13:53:25 +030070RemoveSwitchFallThroughTraverser::RemoveSwitchFallThroughTraverser(TIntermBlock *statementList)
Olli Etuaho2cd7a0e2015-02-27 13:57:32 +020071 : TIntermTraverser(true, false, false),
72 mStatementList(statementList),
73 mLastStatementWasBreak(false),
74 mPreviousCase(nullptr)
75{
Olli Etuaho6d40bbd2016-09-30 13:49:38 +010076 mStatementListOut = new TIntermBlock();
Olli Etuaho2cd7a0e2015-02-27 13:57:32 +020077}
78
Olli Etuahoaf5070f2017-10-10 13:53:25 +030079void RemoveSwitchFallThroughTraverser::visitSymbol(TIntermSymbol *node)
Olli Etuaho2cd7a0e2015-02-27 13:57:32 +020080{
81 // Note that this assumes that switch statements which don't begin by a case statement
82 // have already been weeded out in validation.
83 mPreviousCase->getSequence()->push_back(node);
84 mLastStatementWasBreak = false;
85}
86
Olli Etuahoaf5070f2017-10-10 13:53:25 +030087void RemoveSwitchFallThroughTraverser::visitConstantUnion(TIntermConstantUnion *node)
Olli Etuaho2cd7a0e2015-02-27 13:57:32 +020088{
89 // Conditions of case labels are not traversed, so this is some other constant
90 // Could be just a statement like "0;"
91 mPreviousCase->getSequence()->push_back(node);
92 mLastStatementWasBreak = false;
93}
94
Olli Etuaho78507c62017-10-10 15:06:45 +030095bool RemoveSwitchFallThroughTraverser::visitDeclaration(Visit, TIntermDeclaration *node)
96{
97 mPreviousCase->getSequence()->push_back(node);
98 mLastStatementWasBreak = false;
99 return false;
100}
101
Olli Etuahoaf5070f2017-10-10 13:53:25 +0300102bool RemoveSwitchFallThroughTraverser::visitBinary(Visit, TIntermBinary *node)
Olli Etuaho2cd7a0e2015-02-27 13:57:32 +0200103{
104 mPreviousCase->getSequence()->push_back(node);
105 mLastStatementWasBreak = false;
106 return false;
107}
108
Olli Etuahoaf5070f2017-10-10 13:53:25 +0300109bool RemoveSwitchFallThroughTraverser::visitUnary(Visit, TIntermUnary *node)
Olli Etuaho2cd7a0e2015-02-27 13:57:32 +0200110{
111 mPreviousCase->getSequence()->push_back(node);
112 mLastStatementWasBreak = false;
113 return false;
114}
115
Olli Etuahoaf5070f2017-10-10 13:53:25 +0300116bool RemoveSwitchFallThroughTraverser::visitTernary(Visit, TIntermTernary *node)
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300117{
118 mPreviousCase->getSequence()->push_back(node);
119 mLastStatementWasBreak = false;
120 return false;
121}
122
Olli Etuaho78507c62017-10-10 15:06:45 +0300123bool RemoveSwitchFallThroughTraverser::visitSwizzle(Visit, TIntermSwizzle *node)
124{
125 mPreviousCase->getSequence()->push_back(node);
126 mLastStatementWasBreak = false;
127 return false;
128}
129
Olli Etuahoaf5070f2017-10-10 13:53:25 +0300130bool RemoveSwitchFallThroughTraverser::visitIfElse(Visit, TIntermIfElse *node)
Olli Etuaho2cd7a0e2015-02-27 13:57:32 +0200131{
132 mPreviousCase->getSequence()->push_back(node);
133 mLastStatementWasBreak = false;
134 return false;
135}
136
Olli Etuahoaf5070f2017-10-10 13:53:25 +0300137bool RemoveSwitchFallThroughTraverser::visitSwitch(Visit, TIntermSwitch *node)
Olli Etuaho2cd7a0e2015-02-27 13:57:32 +0200138{
139 mPreviousCase->getSequence()->push_back(node);
140 mLastStatementWasBreak = false;
141 // Don't go into nested switch statements
142 return false;
143}
144
Olli Etuahoaf5070f2017-10-10 13:53:25 +0300145void RemoveSwitchFallThroughTraverser::outputSequence(TIntermSequence *sequence, size_t startIndex)
Olli Etuaho2cd7a0e2015-02-27 13:57:32 +0200146{
147 for (size_t i = startIndex; i < sequence->size(); ++i)
148 {
149 mStatementListOut->getSequence()->push_back(sequence->at(i));
150 }
151}
152
Olli Etuahoaf5070f2017-10-10 13:53:25 +0300153void RemoveSwitchFallThroughTraverser::handlePreviousCase()
Olli Etuaho2cd7a0e2015-02-27 13:57:32 +0200154{
155 if (mPreviousCase)
156 mCasesSharingBreak.push_back(mPreviousCase);
157 if (mLastStatementWasBreak)
158 {
159 bool labelsWithNoStatements = true;
160 for (size_t i = 0; i < mCasesSharingBreak.size(); ++i)
161 {
162 if (mCasesSharingBreak.at(i)->getSequence()->size() > 1)
163 {
164 labelsWithNoStatements = false;
165 }
166 if (labelsWithNoStatements)
167 {
168 // Fall-through is allowed in case the label has no statements.
169 outputSequence(mCasesSharingBreak.at(i)->getSequence(), 0);
170 }
171 else
172 {
173 // Include all the statements that this case can fall through under the same label.
174 for (size_t j = i; j < mCasesSharingBreak.size(); ++j)
175 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500176 size_t startIndex =
177 j > i ? 1 : 0; // Add the label only from the first sequence.
Olli Etuaho2cd7a0e2015-02-27 13:57:32 +0200178 outputSequence(mCasesSharingBreak.at(j)->getSequence(), startIndex);
Olli Etuaho2cd7a0e2015-02-27 13:57:32 +0200179 }
180 }
181 }
182 mCasesSharingBreak.clear();
183 }
184 mLastStatementWasBreak = false;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500185 mPreviousCase = nullptr;
Olli Etuaho2cd7a0e2015-02-27 13:57:32 +0200186}
187
Olli Etuahoaf5070f2017-10-10 13:53:25 +0300188bool RemoveSwitchFallThroughTraverser::visitCase(Visit, TIntermCase *node)
Olli Etuaho2cd7a0e2015-02-27 13:57:32 +0200189{
190 handlePreviousCase();
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100191 mPreviousCase = new TIntermBlock();
Olli Etuaho2cd7a0e2015-02-27 13:57:32 +0200192 mPreviousCase->getSequence()->push_back(node);
193 // Don't traverse the condition of the case statement
194 return false;
195}
196
Olli Etuahoaf5070f2017-10-10 13:53:25 +0300197bool RemoveSwitchFallThroughTraverser::visitAggregate(Visit, TIntermAggregate *node)
Olli Etuaho2cd7a0e2015-02-27 13:57:32 +0200198{
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100199 mPreviousCase->getSequence()->push_back(node);
200 mLastStatementWasBreak = false;
201 return false;
202}
203
Olli Etuahoaf5070f2017-10-10 13:53:25 +0300204bool RemoveSwitchFallThroughTraverser::visitBlock(Visit, TIntermBlock *node)
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100205{
Olli Etuaho2cd7a0e2015-02-27 13:57:32 +0200206 if (node != mStatementList)
207 {
208 mPreviousCase->getSequence()->push_back(node);
209 mLastStatementWasBreak = false;
210 return false;
211 }
212 return true;
213}
214
Olli Etuahoaf5070f2017-10-10 13:53:25 +0300215bool RemoveSwitchFallThroughTraverser::visitLoop(Visit, TIntermLoop *node)
Olli Etuaho2cd7a0e2015-02-27 13:57:32 +0200216{
217 mPreviousCase->getSequence()->push_back(node);
218 mLastStatementWasBreak = false;
219 return false;
220}
221
Olli Etuahoaf5070f2017-10-10 13:53:25 +0300222bool RemoveSwitchFallThroughTraverser::visitBranch(Visit, TIntermBranch *node)
Olli Etuaho2cd7a0e2015-02-27 13:57:32 +0200223{
224 mPreviousCase->getSequence()->push_back(node);
225 // TODO: Verify that accepting return or continue statements here doesn't cause problems.
226 mLastStatementWasBreak = true;
227 return false;
228}
Jamie Madill45bcc782016-11-07 13:58:48 -0500229
Olli Etuahoaf5070f2017-10-10 13:53:25 +0300230} // anonymous namespace
231
232TIntermBlock *RemoveSwitchFallThrough(TIntermBlock *statementList)
233{
234 return RemoveSwitchFallThroughTraverser::removeFallThrough(statementList);
235}
236
Jamie Madill45bcc782016-11-07 13:58:48 -0500237} // namespace sh