blob: b756f2d762db346235dac072a3cc477061ff3100 [file] [log] [blame]
ethannicholas22f939e2016-10-13 13:25:34 -07001/*
2 * Copyright 2016 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
Ethan Nicholas0df1b042017-03-31 13:56:23 -04007
ethannicholas22f939e2016-10-13 13:25:34 -07008#include "SkSLCFGGenerator.h"
9
10#include "ir/SkSLConstructor.h"
11#include "ir/SkSLBinaryExpression.h"
12#include "ir/SkSLDoStatement.h"
13#include "ir/SkSLExpressionStatement.h"
14#include "ir/SkSLFieldAccess.h"
15#include "ir/SkSLForStatement.h"
16#include "ir/SkSLFunctionCall.h"
17#include "ir/SkSLIfStatement.h"
18#include "ir/SkSLIndexExpression.h"
19#include "ir/SkSLPostfixExpression.h"
20#include "ir/SkSLPrefixExpression.h"
21#include "ir/SkSLReturnStatement.h"
22#include "ir/SkSLSwizzle.h"
Ethan Nicholasaf197692017-02-27 13:26:45 -050023#include "ir/SkSLSwitchStatement.h"
ethannicholas22f939e2016-10-13 13:25:34 -070024#include "ir/SkSLTernaryExpression.h"
25#include "ir/SkSLVarDeclarationsStatement.h"
26#include "ir/SkSLWhileStatement.h"
27
28namespace SkSL {
29
30BlockId CFG::newBlock() {
31 BlockId result = fBlocks.size();
32 fBlocks.emplace_back();
33 if (fBlocks.size() > 1) {
34 this->addExit(fCurrent, result);
35 }
36 fCurrent = result;
37 return result;
38}
39
40BlockId CFG::newIsolatedBlock() {
41 BlockId result = fBlocks.size();
42 fBlocks.emplace_back();
43 return result;
44}
45
46void CFG::addExit(BlockId from, BlockId to) {
47 if (from == 0 || fBlocks[from].fEntrances.size()) {
48 fBlocks[from].fExits.insert(to);
49 fBlocks[to].fEntrances.insert(from);
50 }
51}
52
53void CFG::dump() {
54 for (size_t i = 0; i < fBlocks.size(); i++) {
55 printf("Block %d\n-------\nBefore: ", (int) i);
56 const char* separator = "";
57 for (auto iter = fBlocks[i].fBefore.begin(); iter != fBlocks[i].fBefore.end(); iter++) {
Ethan Nicholas86a43402017-01-19 13:32:00 -050058 printf("%s%s = %s", separator, iter->first->description().c_str(),
Ethan Nicholascb670962017-04-20 19:31:52 -040059 iter->second ? (*iter->second)->description().c_str() : "<undefined>");
ethannicholas22f939e2016-10-13 13:25:34 -070060 separator = ", ";
61 }
62 printf("\nEntrances: ");
63 separator = "";
64 for (BlockId b : fBlocks[i].fEntrances) {
65 printf("%s%d", separator, (int) b);
66 separator = ", ";
67 }
68 printf("\n");
69 for (size_t j = 0; j < fBlocks[i].fNodes.size(); j++) {
Ethan Nicholas86a43402017-01-19 13:32:00 -050070 BasicBlock::Node& n = fBlocks[i].fNodes[j];
Ethan Nicholascb670962017-04-20 19:31:52 -040071 printf("Node %d (%p): %s\n", (int) j, &n, n.fKind == BasicBlock::Node::kExpression_Kind
72 ? (*n.expression())->description().c_str()
73 : (*n.statement())->description().c_str());
ethannicholas22f939e2016-10-13 13:25:34 -070074 }
75 printf("Exits: ");
76 separator = "";
77 for (BlockId b : fBlocks[i].fExits) {
78 printf("%s%d", separator, (int) b);
79 separator = ", ";
80 }
81 printf("\n\n");
82 }
83}
84
Ethan Nicholascb670962017-04-20 19:31:52 -040085bool BasicBlock::tryRemoveExpressionBefore(std::vector<BasicBlock::Node>::iterator* iter,
86 Expression* e) {
87 if (e->fKind == Expression::kTernary_Kind) {
88 return false;
89 }
90 bool result;
91 if ((*iter)->fKind == BasicBlock::Node::kExpression_Kind) {
92 ASSERT((*iter)->expression()->get() != e);
93 Expression* old = (*iter)->expression()->get();
94 do {
95 if ((*iter) == fNodes.begin()) {
96 ABORT("couldn't find %s before %s\n", e->description().c_str(),
97 old->description().c_str());
98 }
99 --(*iter);
100 } while ((*iter)->fKind != BasicBlock::Node::kExpression_Kind ||
101 (*iter)->expression()->get() != e);
102 result = this->tryRemoveExpression(iter);
103 while ((*iter)->fKind != BasicBlock::Node::kExpression_Kind ||
104 (*iter)->expression()->get() != old) {
105 ASSERT(*iter != fNodes.end());
106 ++(*iter);
107 }
108 } else {
109 Statement* old = (*iter)->statement()->get();
110 do {
111 if ((*iter) == fNodes.begin()) {
112 ABORT("couldn't find %s before %s\n", e->description().c_str(),
113 old->description().c_str());
114 }
115 --(*iter);
116 } while ((*iter)->fKind != BasicBlock::Node::kExpression_Kind ||
117 (*iter)->expression()->get() != e);
118 result = this->tryRemoveExpression(iter);
119 while ((*iter)->fKind != BasicBlock::Node::kStatement_Kind ||
120 (*iter)->statement()->get() != old) {
121 ASSERT(*iter != fNodes.end());
122 ++(*iter);
123 }
124 }
125 return result;
126}
127
128bool BasicBlock::tryRemoveLValueBefore(std::vector<BasicBlock::Node>::iterator* iter,
129 Expression* lvalue) {
130 switch (lvalue->fKind) {
131 case Expression::kVariableReference_Kind:
132 return true;
133 case Expression::kSwizzle_Kind:
134 return this->tryRemoveLValueBefore(iter, ((Swizzle*) lvalue)->fBase.get());
135 case Expression::kFieldAccess_Kind:
136 return this->tryRemoveLValueBefore(iter, ((FieldAccess*) lvalue)->fBase.get());
137 case Expression::kIndex_Kind:
138 if (!this->tryRemoveLValueBefore(iter, ((IndexExpression*) lvalue)->fBase.get())) {
139 return false;
140 }
141 return this->tryRemoveExpressionBefore(iter, ((IndexExpression*) lvalue)->fIndex.get());
142 default:
143 ABORT("invalid lvalue: %s\n", lvalue->description().c_str());
144 }
145}
146
147bool BasicBlock::tryRemoveExpression(std::vector<BasicBlock::Node>::iterator* iter) {
148 Expression* expr = (*iter)->expression()->get();
149 switch (expr->fKind) {
150 case Expression::kBinary_Kind: {
151 BinaryExpression* b = (BinaryExpression*) expr;
152 if (b->fOperator == Token::EQ) {
153 if (!this->tryRemoveLValueBefore(iter, b->fLeft.get())) {
154 return false;
155 }
156 } else if (!this->tryRemoveExpressionBefore(iter, b->fLeft.get())) {
157 return false;
158 }
159 if (!this->tryRemoveExpressionBefore(iter, b->fRight.get())) {
160 return false;
161 }
162 ASSERT((*iter)->expression()->get() == expr);
163 *iter = fNodes.erase(*iter);
164 return true;
165 }
166 case Expression::kTernary_Kind: {
167 // ternaries cross basic block boundaries, must regenerate the CFG to remove it
168 return false;
169 }
170 case Expression::kFieldAccess_Kind: {
171 FieldAccess* f = (FieldAccess*) expr;
172 if (!this->tryRemoveExpressionBefore(iter, f->fBase.get())) {
173 return false;
174 }
175 *iter = fNodes.erase(*iter);
176 return true;
177 }
178 case Expression::kSwizzle_Kind: {
179 Swizzle* s = (Swizzle*) expr;
180 if (!this->tryRemoveExpressionBefore(iter, s->fBase.get())) {
181 return false;
182 }
183 *iter = fNodes.erase(*iter);
184 return true;
185 }
186 case Expression::kIndex_Kind: {
187 IndexExpression* idx = (IndexExpression*) expr;
188 if (!this->tryRemoveExpressionBefore(iter, idx->fBase.get())) {
189 return false;
190 }
191 if (!this->tryRemoveExpressionBefore(iter, idx->fIndex.get())) {
192 return false;
193 }
194 *iter = fNodes.erase(*iter);
195 return true;
196 }
197 case Expression::kConstructor_Kind: {
198 Constructor* c = (Constructor*) expr;
199 for (auto& arg : c->fArguments) {
200 if (!this->tryRemoveExpressionBefore(iter, arg.get())) {
201 return false;
202 }
203 ASSERT((*iter)->expression()->get() == expr);
204 }
205 *iter = fNodes.erase(*iter);
206 return true;
207 }
208 case Expression::kFunctionCall_Kind: {
209 FunctionCall* f = (FunctionCall*) expr;
210 for (auto& arg : f->fArguments) {
211 if (!this->tryRemoveExpressionBefore(iter, arg.get())) {
212 return false;
213 }
214 ASSERT((*iter)->expression()->get() == expr);
215 }
216 *iter = fNodes.erase(*iter);
217 return true;
218 }
219 case Expression::kPrefix_Kind:
220 if (!this->tryRemoveExpressionBefore(iter,
221 ((PrefixExpression*) expr)->fOperand.get())) {
222 return false;
223 }
224 *iter = fNodes.erase(*iter);
225 return true;
226 case Expression::kPostfix_Kind:
227 if (!this->tryRemoveExpressionBefore(iter,
228 ((PrefixExpression*) expr)->fOperand.get())) {
229 return false;
230 }
231 *iter = fNodes.erase(*iter);
232 return true;
233 case Expression::kBoolLiteral_Kind: // fall through
234 case Expression::kFloatLiteral_Kind: // fall through
235 case Expression::kIntLiteral_Kind: // fall through
236 case Expression::kVariableReference_Kind:
237 *iter = fNodes.erase(*iter);
238 return true;
239 default:
240 ABORT("unhandled expression: %s\n", expr->description().c_str());
241 }
242}
243
244bool BasicBlock::tryInsertExpression(std::vector<BasicBlock::Node>::iterator* iter,
245 std::unique_ptr<Expression>* expr) {
246 switch ((*expr)->fKind) {
247 case Expression::kBinary_Kind: {
248 BinaryExpression* b = (BinaryExpression*) expr->get();
249 if (!this->tryInsertExpression(iter, &b->fRight)) {
250 return false;
251 }
252 ++(*iter);
253 if (!this->tryInsertExpression(iter, &b->fLeft)) {
254 return false;
255 }
256 ++(*iter);
257 BasicBlock::Node node = { BasicBlock::Node::kExpression_Kind, true, expr, nullptr };
258 *iter = fNodes.insert(*iter, node);
259 return true;
260 }
261 case Expression::kBoolLiteral_Kind: // fall through
262 case Expression::kFloatLiteral_Kind: // fall through
263 case Expression::kIntLiteral_Kind: // fall through
264 case Expression::kVariableReference_Kind: {
265 BasicBlock::Node node = { BasicBlock::Node::kExpression_Kind, true, expr, nullptr };
266 *iter = fNodes.insert(*iter, node);
267 return true;
268 }
269 case Expression::kConstructor_Kind: {
270 Constructor* c = (Constructor*) expr->get();
271 for (auto& arg : c->fArguments) {
272 if (!this->tryInsertExpression(iter, &arg)) {
273 return false;
274 }
275 ++(*iter);
276 }
277 BasicBlock::Node node = { BasicBlock::Node::kExpression_Kind, true, expr, nullptr };
278 *iter = fNodes.insert(*iter, node);
279 return true;
280 }
281 default:
282 return false;
283 }
284}
285
Ethan Nicholas86a43402017-01-19 13:32:00 -0500286void CFGGenerator::addExpression(CFG& cfg, std::unique_ptr<Expression>* e, bool constantPropagate) {
287 ASSERT(e);
288 switch ((*e)->fKind) {
ethannicholas22f939e2016-10-13 13:25:34 -0700289 case Expression::kBinary_Kind: {
Ethan Nicholas86a43402017-01-19 13:32:00 -0500290 BinaryExpression* b = (BinaryExpression*) e->get();
ethannicholas22f939e2016-10-13 13:25:34 -0700291 switch (b->fOperator) {
292 case Token::LOGICALAND: // fall through
293 case Token::LOGICALOR: {
294 // this isn't as precise as it could be -- we don't bother to track that if we
295 // early exit from a logical and/or, we know which branch of an 'if' we're going
296 // to hit -- but it won't make much difference in practice.
Ethan Nicholas86a43402017-01-19 13:32:00 -0500297 this->addExpression(cfg, &b->fLeft, constantPropagate);
ethannicholas22f939e2016-10-13 13:25:34 -0700298 BlockId start = cfg.fCurrent;
299 cfg.newBlock();
Ethan Nicholas86a43402017-01-19 13:32:00 -0500300 this->addExpression(cfg, &b->fRight, constantPropagate);
ethannicholas22f939e2016-10-13 13:25:34 -0700301 cfg.newBlock();
302 cfg.addExit(start, cfg.fCurrent);
303 break;
304 }
305 case Token::EQ: {
Ethan Nicholas86a43402017-01-19 13:32:00 -0500306 this->addExpression(cfg, &b->fRight, constantPropagate);
307 this->addLValue(cfg, &b->fLeft);
308 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({
309 BasicBlock::Node::kExpression_Kind,
310 constantPropagate,
311 e,
312 nullptr
ethannicholas22f939e2016-10-13 13:25:34 -0700313 });
314 break;
315 }
316 default:
Ethan Nicholas86a43402017-01-19 13:32:00 -0500317 this->addExpression(cfg, &b->fLeft, !Token::IsAssignment(b->fOperator));
318 this->addExpression(cfg, &b->fRight, constantPropagate);
319 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({
320 BasicBlock::Node::kExpression_Kind,
321 constantPropagate,
322 e,
323 nullptr
ethannicholas22f939e2016-10-13 13:25:34 -0700324 });
325 }
326 break;
327 }
328 case Expression::kConstructor_Kind: {
Ethan Nicholas86a43402017-01-19 13:32:00 -0500329 Constructor* c = (Constructor*) e->get();
330 for (auto& arg : c->fArguments) {
331 this->addExpression(cfg, &arg, constantPropagate);
ethannicholas22f939e2016-10-13 13:25:34 -0700332 }
Ethan Nicholas86a43402017-01-19 13:32:00 -0500333 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpression_Kind,
334 constantPropagate, e, nullptr });
ethannicholas22f939e2016-10-13 13:25:34 -0700335 break;
336 }
337 case Expression::kFunctionCall_Kind: {
Ethan Nicholas86a43402017-01-19 13:32:00 -0500338 FunctionCall* c = (FunctionCall*) e->get();
339 for (auto& arg : c->fArguments) {
340 this->addExpression(cfg, &arg, constantPropagate);
ethannicholas22f939e2016-10-13 13:25:34 -0700341 }
Ethan Nicholas86a43402017-01-19 13:32:00 -0500342 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpression_Kind,
343 constantPropagate, e, nullptr });
ethannicholas22f939e2016-10-13 13:25:34 -0700344 break;
345 }
346 case Expression::kFieldAccess_Kind:
Ethan Nicholas86a43402017-01-19 13:32:00 -0500347 this->addExpression(cfg, &((FieldAccess*) e->get())->fBase, constantPropagate);
348 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpression_Kind,
349 constantPropagate, e, nullptr });
ethannicholas22f939e2016-10-13 13:25:34 -0700350 break;
351 case Expression::kIndex_Kind:
Ethan Nicholas86a43402017-01-19 13:32:00 -0500352 this->addExpression(cfg, &((IndexExpression*) e->get())->fBase, constantPropagate);
353 this->addExpression(cfg, &((IndexExpression*) e->get())->fIndex, constantPropagate);
354 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpression_Kind,
355 constantPropagate, e, nullptr });
ethannicholas22f939e2016-10-13 13:25:34 -0700356 break;
Ethan Nicholasaf197692017-02-27 13:26:45 -0500357 case Expression::kPrefix_Kind: {
358 PrefixExpression* p = (PrefixExpression*) e->get();
359 this->addExpression(cfg, &p->fOperand, constantPropagate &&
360 p->fOperator != Token::PLUSPLUS &&
361 p->fOperator != Token::MINUSMINUS);
Ethan Nicholas86a43402017-01-19 13:32:00 -0500362 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpression_Kind,
363 constantPropagate, e, nullptr });
ethannicholas22f939e2016-10-13 13:25:34 -0700364 break;
Ethan Nicholasaf197692017-02-27 13:26:45 -0500365 }
ethannicholas22f939e2016-10-13 13:25:34 -0700366 case Expression::kPostfix_Kind:
Ethan Nicholasaf197692017-02-27 13:26:45 -0500367 this->addExpression(cfg, &((PostfixExpression*) e->get())->fOperand, false);
Ethan Nicholas86a43402017-01-19 13:32:00 -0500368 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpression_Kind,
369 constantPropagate, e, nullptr });
ethannicholas22f939e2016-10-13 13:25:34 -0700370 break;
371 case Expression::kSwizzle_Kind:
Ethan Nicholas86a43402017-01-19 13:32:00 -0500372 this->addExpression(cfg, &((Swizzle*) e->get())->fBase, constantPropagate);
373 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpression_Kind,
374 constantPropagate, e, nullptr });
ethannicholas22f939e2016-10-13 13:25:34 -0700375 break;
376 case Expression::kBoolLiteral_Kind: // fall through
377 case Expression::kFloatLiteral_Kind: // fall through
378 case Expression::kIntLiteral_Kind: // fall through
379 case Expression::kVariableReference_Kind:
Ethan Nicholas86a43402017-01-19 13:32:00 -0500380 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpression_Kind,
381 constantPropagate, e, nullptr });
ethannicholas22f939e2016-10-13 13:25:34 -0700382 break;
383 case Expression::kTernary_Kind: {
Ethan Nicholas86a43402017-01-19 13:32:00 -0500384 TernaryExpression* t = (TernaryExpression*) e->get();
385 this->addExpression(cfg, &t->fTest, constantPropagate);
Ethan Nicholascb670962017-04-20 19:31:52 -0400386 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpression_Kind,
387 constantPropagate, e, nullptr });
ethannicholas22f939e2016-10-13 13:25:34 -0700388 BlockId start = cfg.fCurrent;
389 cfg.newBlock();
Ethan Nicholas86a43402017-01-19 13:32:00 -0500390 this->addExpression(cfg, &t->fIfTrue, constantPropagate);
ethannicholas22f939e2016-10-13 13:25:34 -0700391 BlockId next = cfg.newBlock();
392 cfg.fCurrent = start;
393 cfg.newBlock();
Ethan Nicholas86a43402017-01-19 13:32:00 -0500394 this->addExpression(cfg, &t->fIfFalse, constantPropagate);
ethannicholas22f939e2016-10-13 13:25:34 -0700395 cfg.addExit(cfg.fCurrent, next);
396 cfg.fCurrent = next;
397 break;
398 }
399 case Expression::kFunctionReference_Kind: // fall through
400 case Expression::kTypeReference_Kind: // fall through
401 case Expression::kDefined_Kind:
402 ASSERT(false);
403 break;
404 }
405}
406
407// adds expressions that are evaluated as part of resolving an lvalue
Ethan Nicholas86a43402017-01-19 13:32:00 -0500408void CFGGenerator::addLValue(CFG& cfg, std::unique_ptr<Expression>* e) {
409 switch ((*e)->fKind) {
ethannicholas22f939e2016-10-13 13:25:34 -0700410 case Expression::kFieldAccess_Kind:
Ethan Nicholas86a43402017-01-19 13:32:00 -0500411 this->addLValue(cfg, &((FieldAccess&) **e).fBase);
ethannicholas22f939e2016-10-13 13:25:34 -0700412 break;
413 case Expression::kIndex_Kind:
Ethan Nicholas86a43402017-01-19 13:32:00 -0500414 this->addLValue(cfg, &((IndexExpression&) **e).fBase);
415 this->addExpression(cfg, &((IndexExpression&) **e).fIndex, true);
ethannicholas22f939e2016-10-13 13:25:34 -0700416 break;
417 case Expression::kSwizzle_Kind:
Ethan Nicholas86a43402017-01-19 13:32:00 -0500418 this->addLValue(cfg, &((Swizzle&) **e).fBase);
ethannicholas22f939e2016-10-13 13:25:34 -0700419 break;
420 case Expression::kVariableReference_Kind:
421 break;
422 default:
423 // not an lvalue, can't happen
424 ASSERT(false);
425 break;
426 }
427}
428
Ethan Nicholascb670962017-04-20 19:31:52 -0400429void CFGGenerator::addStatement(CFG& cfg, std::unique_ptr<Statement>* s) {
430 switch ((*s)->fKind) {
ethannicholas22f939e2016-10-13 13:25:34 -0700431 case Statement::kBlock_Kind:
Ethan Nicholascb670962017-04-20 19:31:52 -0400432 for (auto& child : ((Block&) **s).fStatements) {
433 addStatement(cfg, &child);
ethannicholas22f939e2016-10-13 13:25:34 -0700434 }
435 break;
436 case Statement::kIf_Kind: {
Ethan Nicholascb670962017-04-20 19:31:52 -0400437 IfStatement& ifs = (IfStatement&) **s;
438 this->addExpression(cfg, &ifs.fTest, true);
439 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kStatement_Kind, false,
440 nullptr, s });
ethannicholas22f939e2016-10-13 13:25:34 -0700441 BlockId start = cfg.fCurrent;
442 cfg.newBlock();
Ethan Nicholascb670962017-04-20 19:31:52 -0400443 this->addStatement(cfg, &ifs.fIfTrue);
ethannicholas22f939e2016-10-13 13:25:34 -0700444 BlockId next = cfg.newBlock();
Ethan Nicholascb670962017-04-20 19:31:52 -0400445 if (ifs.fIfFalse) {
ethannicholas22f939e2016-10-13 13:25:34 -0700446 cfg.fCurrent = start;
447 cfg.newBlock();
Ethan Nicholascb670962017-04-20 19:31:52 -0400448 this->addStatement(cfg, &ifs.fIfFalse);
ethannicholas22f939e2016-10-13 13:25:34 -0700449 cfg.addExit(cfg.fCurrent, next);
450 cfg.fCurrent = next;
451 } else {
452 cfg.addExit(start, next);
453 }
454 break;
455 }
456 case Statement::kExpression_Kind: {
Ethan Nicholascb670962017-04-20 19:31:52 -0400457 this->addExpression(cfg, &((ExpressionStatement&) **s).fExpression, true);
458 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kStatement_Kind, false,
459 nullptr, s });
ethannicholas22f939e2016-10-13 13:25:34 -0700460 break;
461 }
462 case Statement::kVarDeclarations_Kind: {
Ethan Nicholascb670962017-04-20 19:31:52 -0400463 VarDeclarationsStatement& decls = ((VarDeclarationsStatement&) **s);
Ethan Nicholas86a43402017-01-19 13:32:00 -0500464 for (auto& vd : decls.fDeclaration->fVars) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400465 if (vd->fValue) {
466 this->addExpression(cfg, &vd->fValue, true);
ethannicholas22f939e2016-10-13 13:25:34 -0700467 }
468 }
Ethan Nicholas86a43402017-01-19 13:32:00 -0500469 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kStatement_Kind, false,
470 nullptr, s });
ethannicholas22f939e2016-10-13 13:25:34 -0700471 break;
472 }
473 case Statement::kDiscard_Kind:
Ethan Nicholas86a43402017-01-19 13:32:00 -0500474 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kStatement_Kind, false,
475 nullptr, s });
ethannicholas22f939e2016-10-13 13:25:34 -0700476 cfg.fCurrent = cfg.newIsolatedBlock();
477 break;
478 case Statement::kReturn_Kind: {
Ethan Nicholascb670962017-04-20 19:31:52 -0400479 ReturnStatement& r = ((ReturnStatement&) **s);
ethannicholas22f939e2016-10-13 13:25:34 -0700480 if (r.fExpression) {
Ethan Nicholas86a43402017-01-19 13:32:00 -0500481 this->addExpression(cfg, &r.fExpression, true);
ethannicholas22f939e2016-10-13 13:25:34 -0700482 }
Ethan Nicholas86a43402017-01-19 13:32:00 -0500483 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kStatement_Kind, false,
484 nullptr, s });
ethannicholas22f939e2016-10-13 13:25:34 -0700485 cfg.fCurrent = cfg.newIsolatedBlock();
486 break;
487 }
488 case Statement::kBreak_Kind:
Ethan Nicholas86a43402017-01-19 13:32:00 -0500489 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kStatement_Kind, false,
490 nullptr, s });
ethannicholas22f939e2016-10-13 13:25:34 -0700491 cfg.addExit(cfg.fCurrent, fLoopExits.top());
492 cfg.fCurrent = cfg.newIsolatedBlock();
493 break;
494 case Statement::kContinue_Kind:
Ethan Nicholas86a43402017-01-19 13:32:00 -0500495 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kStatement_Kind, false,
496 nullptr, s });
ethannicholas22f939e2016-10-13 13:25:34 -0700497 cfg.addExit(cfg.fCurrent, fLoopContinues.top());
498 cfg.fCurrent = cfg.newIsolatedBlock();
499 break;
500 case Statement::kWhile_Kind: {
Ethan Nicholascb670962017-04-20 19:31:52 -0400501 WhileStatement& w = (WhileStatement&) **s;
ethannicholas22f939e2016-10-13 13:25:34 -0700502 BlockId loopStart = cfg.newBlock();
503 fLoopContinues.push(loopStart);
504 BlockId loopExit = cfg.newIsolatedBlock();
505 fLoopExits.push(loopExit);
Ethan Nicholascb670962017-04-20 19:31:52 -0400506 this->addExpression(cfg, &w.fTest, true);
ethannicholas22f939e2016-10-13 13:25:34 -0700507 BlockId test = cfg.fCurrent;
508 cfg.addExit(test, loopExit);
509 cfg.newBlock();
Ethan Nicholascb670962017-04-20 19:31:52 -0400510 this->addStatement(cfg, &w.fStatement);
ethannicholas22f939e2016-10-13 13:25:34 -0700511 cfg.addExit(cfg.fCurrent, loopStart);
512 fLoopContinues.pop();
513 fLoopExits.pop();
514 cfg.fCurrent = loopExit;
515 break;
516 }
517 case Statement::kDo_Kind: {
Ethan Nicholascb670962017-04-20 19:31:52 -0400518 DoStatement& d = (DoStatement&) **s;
ethannicholas22f939e2016-10-13 13:25:34 -0700519 BlockId loopStart = cfg.newBlock();
520 fLoopContinues.push(loopStart);
521 BlockId loopExit = cfg.newIsolatedBlock();
522 fLoopExits.push(loopExit);
Ethan Nicholascb670962017-04-20 19:31:52 -0400523 this->addStatement(cfg, &d.fStatement);
524 this->addExpression(cfg, &d.fTest, true);
ethannicholas22f939e2016-10-13 13:25:34 -0700525 cfg.addExit(cfg.fCurrent, loopExit);
526 cfg.addExit(cfg.fCurrent, loopStart);
527 fLoopContinues.pop();
528 fLoopExits.pop();
529 cfg.fCurrent = loopExit;
530 break;
531 }
532 case Statement::kFor_Kind: {
Ethan Nicholascb670962017-04-20 19:31:52 -0400533 ForStatement& f = (ForStatement&) **s;
534 if (f.fInitializer) {
535 this->addStatement(cfg, &f.fInitializer);
ethannicholas22f939e2016-10-13 13:25:34 -0700536 }
537 BlockId loopStart = cfg.newBlock();
538 BlockId next = cfg.newIsolatedBlock();
539 fLoopContinues.push(next);
540 BlockId loopExit = cfg.newIsolatedBlock();
541 fLoopExits.push(loopExit);
Ethan Nicholascb670962017-04-20 19:31:52 -0400542 if (f.fTest) {
543 this->addExpression(cfg, &f.fTest, true);
ethannicholas22f939e2016-10-13 13:25:34 -0700544 BlockId test = cfg.fCurrent;
545 cfg.addExit(test, loopExit);
546 }
547 cfg.newBlock();
Ethan Nicholascb670962017-04-20 19:31:52 -0400548 this->addStatement(cfg, &f.fStatement);
ethannicholas22f939e2016-10-13 13:25:34 -0700549 cfg.addExit(cfg.fCurrent, next);
550 cfg.fCurrent = next;
Ethan Nicholascb670962017-04-20 19:31:52 -0400551 if (f.fNext) {
552 this->addExpression(cfg, &f.fNext, true);
ethannicholas22f939e2016-10-13 13:25:34 -0700553 }
Ethan Nicholas86a43402017-01-19 13:32:00 -0500554 cfg.addExit(cfg.fCurrent, loopStart);
ethannicholas22f939e2016-10-13 13:25:34 -0700555 fLoopContinues.pop();
556 fLoopExits.pop();
557 cfg.fCurrent = loopExit;
558 break;
559 }
Ethan Nicholasaf197692017-02-27 13:26:45 -0500560 case Statement::kSwitch_Kind: {
Ethan Nicholascb670962017-04-20 19:31:52 -0400561 SwitchStatement& ss = (SwitchStatement&) **s;
562 this->addExpression(cfg, &ss.fValue, true);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -0400563 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kStatement_Kind, false,
564 nullptr, s });
Ethan Nicholasaf197692017-02-27 13:26:45 -0500565 BlockId start = cfg.fCurrent;
566 BlockId switchExit = cfg.newIsolatedBlock();
567 fLoopExits.push(switchExit);
Ethan Nicholascb670962017-04-20 19:31:52 -0400568 for (const auto& c : ss.fCases) {
Ethan Nicholasaf197692017-02-27 13:26:45 -0500569 cfg.newBlock();
570 cfg.addExit(start, cfg.fCurrent);
571 if (c->fValue) {
572 // technically this should go in the start block, but it doesn't actually matter
573 // because it must be constant. Not worth running two loops for.
574 this->addExpression(cfg, &c->fValue, true);
575 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400576 for (auto& caseStatement : c->fStatements) {
577 this->addStatement(cfg, &caseStatement);
Ethan Nicholasaf197692017-02-27 13:26:45 -0500578 }
579 }
580 cfg.addExit(cfg.fCurrent, switchExit);
581 // note that unlike GLSL, our grammar requires the default case to be last
Ethan Nicholascb670962017-04-20 19:31:52 -0400582 if (0 == ss.fCases.size() || ss.fCases[ss.fCases.size() - 1]->fValue) {
Ethan Nicholasaf197692017-02-27 13:26:45 -0500583 // switch does not have a default clause, mark that it can skip straight to the end
584 cfg.addExit(start, switchExit);
585 }
586 fLoopExits.pop();
587 cfg.fCurrent = switchExit;
588 break;
589 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400590 case Statement::kNop_Kind:
591 break;
ethannicholas22f939e2016-10-13 13:25:34 -0700592 default:
Ethan Nicholascb670962017-04-20 19:31:52 -0400593 printf("statement: %s\n", (*s)->description().c_str());
ethannicholas22f939e2016-10-13 13:25:34 -0700594 ABORT("unsupported statement kind");
595 }
596}
597
Ethan Nicholascb670962017-04-20 19:31:52 -0400598CFG CFGGenerator::getCFG(FunctionDefinition& f) {
ethannicholas22f939e2016-10-13 13:25:34 -0700599 CFG result;
600 result.fStart = result.newBlock();
601 result.fCurrent = result.fStart;
Ethan Nicholascb670962017-04-20 19:31:52 -0400602 this->addStatement(result, &f.fBody);
ethannicholas22f939e2016-10-13 13:25:34 -0700603 result.newBlock();
604 result.fExit = result.fCurrent;
605 return result;
606}
607
608} // namespace