1 /*
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 */
7
8 #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"
23 #include "ir/SkSLSwitchStatement.h"
24 #include "ir/SkSLTernaryExpression.h"
25 #include "ir/SkSLVarDeclarationsStatement.h"
26 #include "ir/SkSLWhileStatement.h"
27
28 namespace SkSL {
29
newBlock()30 BlockId 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
newIsolatedBlock()40 BlockId CFG::newIsolatedBlock() {
41 BlockId result = fBlocks.size();
42 fBlocks.emplace_back();
43 return result;
44 }
45
addExit(BlockId from,BlockId to)46 void 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
dump()53 void 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++) {
58 printf("%s%s = %s", separator, iter->first->description().c_str(),
59 iter->second ? (*iter->second)->description().c_str() : "<undefined>");
60 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++) {
70 BasicBlock::Node& n = fBlocks[i].fNodes[j];
71 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());
74 }
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
tryRemoveExpressionBefore(std::vector<BasicBlock::Node>::iterator * iter,Expression * e)85 bool 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 return false;
97 }
98 --(*iter);
99 } while ((*iter)->fKind != BasicBlock::Node::kExpression_Kind ||
100 (*iter)->expression()->get() != e);
101 result = this->tryRemoveExpression(iter);
102 while ((*iter)->fKind != BasicBlock::Node::kExpression_Kind ||
103 (*iter)->expression()->get() != old) {
104 ASSERT(*iter != fNodes.end());
105 ++(*iter);
106 }
107 } else {
108 Statement* old = (*iter)->statement()->get();
109 do {
110 if ((*iter) == fNodes.begin()) {
111 return false;
112 }
113 --(*iter);
114 } while ((*iter)->fKind != BasicBlock::Node::kExpression_Kind ||
115 (*iter)->expression()->get() != e);
116 result = this->tryRemoveExpression(iter);
117 while ((*iter)->fKind != BasicBlock::Node::kStatement_Kind ||
118 (*iter)->statement()->get() != old) {
119 ASSERT(*iter != fNodes.end());
120 ++(*iter);
121 }
122 }
123 return result;
124 }
125
tryRemoveLValueBefore(std::vector<BasicBlock::Node>::iterator * iter,Expression * lvalue)126 bool BasicBlock::tryRemoveLValueBefore(std::vector<BasicBlock::Node>::iterator* iter,
127 Expression* lvalue) {
128 switch (lvalue->fKind) {
129 case Expression::kVariableReference_Kind:
130 return true;
131 case Expression::kSwizzle_Kind:
132 return this->tryRemoveLValueBefore(iter, ((Swizzle*) lvalue)->fBase.get());
133 case Expression::kFieldAccess_Kind:
134 return this->tryRemoveLValueBefore(iter, ((FieldAccess*) lvalue)->fBase.get());
135 case Expression::kIndex_Kind:
136 if (!this->tryRemoveLValueBefore(iter, ((IndexExpression*) lvalue)->fBase.get())) {
137 return false;
138 }
139 return this->tryRemoveExpressionBefore(iter, ((IndexExpression*) lvalue)->fIndex.get());
140 default:
141 ABORT("invalid lvalue: %s\n", lvalue->description().c_str());
142 }
143 }
144
tryRemoveExpression(std::vector<BasicBlock::Node>::iterator * iter)145 bool BasicBlock::tryRemoveExpression(std::vector<BasicBlock::Node>::iterator* iter) {
146 Expression* expr = (*iter)->expression()->get();
147 switch (expr->fKind) {
148 case Expression::kBinary_Kind: {
149 BinaryExpression* b = (BinaryExpression*) expr;
150 if (b->fOperator == Token::EQ) {
151 if (!this->tryRemoveLValueBefore(iter, b->fLeft.get())) {
152 return false;
153 }
154 } else if (!this->tryRemoveExpressionBefore(iter, b->fLeft.get())) {
155 return false;
156 }
157 if (!this->tryRemoveExpressionBefore(iter, b->fRight.get())) {
158 return false;
159 }
160 ASSERT((*iter)->expression()->get() == expr);
161 *iter = fNodes.erase(*iter);
162 return true;
163 }
164 case Expression::kTernary_Kind: {
165 // ternaries cross basic block boundaries, must regenerate the CFG to remove it
166 return false;
167 }
168 case Expression::kFieldAccess_Kind: {
169 FieldAccess* f = (FieldAccess*) expr;
170 if (!this->tryRemoveExpressionBefore(iter, f->fBase.get())) {
171 return false;
172 }
173 *iter = fNodes.erase(*iter);
174 return true;
175 }
176 case Expression::kSwizzle_Kind: {
177 Swizzle* s = (Swizzle*) expr;
178 if (!this->tryRemoveExpressionBefore(iter, s->fBase.get())) {
179 return false;
180 }
181 *iter = fNodes.erase(*iter);
182 return true;
183 }
184 case Expression::kIndex_Kind: {
185 IndexExpression* idx = (IndexExpression*) expr;
186 if (!this->tryRemoveExpressionBefore(iter, idx->fBase.get())) {
187 return false;
188 }
189 if (!this->tryRemoveExpressionBefore(iter, idx->fIndex.get())) {
190 return false;
191 }
192 *iter = fNodes.erase(*iter);
193 return true;
194 }
195 case Expression::kConstructor_Kind: {
196 Constructor* c = (Constructor*) expr;
197 for (auto& arg : c->fArguments) {
198 if (!this->tryRemoveExpressionBefore(iter, arg.get())) {
199 return false;
200 }
201 ASSERT((*iter)->expression()->get() == expr);
202 }
203 *iter = fNodes.erase(*iter);
204 return true;
205 }
206 case Expression::kFunctionCall_Kind: {
207 FunctionCall* f = (FunctionCall*) expr;
208 for (auto& arg : f->fArguments) {
209 if (!this->tryRemoveExpressionBefore(iter, arg.get())) {
210 return false;
211 }
212 ASSERT((*iter)->expression()->get() == expr);
213 }
214 *iter = fNodes.erase(*iter);
215 return true;
216 }
217 case Expression::kPrefix_Kind:
218 if (!this->tryRemoveExpressionBefore(iter,
219 ((PrefixExpression*) expr)->fOperand.get())) {
220 return false;
221 }
222 *iter = fNodes.erase(*iter);
223 return true;
224 case Expression::kPostfix_Kind:
225 if (!this->tryRemoveExpressionBefore(iter,
226 ((PrefixExpression*) expr)->fOperand.get())) {
227 return false;
228 }
229 *iter = fNodes.erase(*iter);
230 return true;
231 case Expression::kBoolLiteral_Kind: // fall through
232 case Expression::kFloatLiteral_Kind: // fall through
233 case Expression::kIntLiteral_Kind: // fall through
234 case Expression::kSetting_Kind: // fall through
235 case Expression::kVariableReference_Kind:
236 *iter = fNodes.erase(*iter);
237 return true;
238 default:
239 ABORT("unhandled expression: %s\n", expr->description().c_str());
240 }
241 }
242
tryInsertExpression(std::vector<BasicBlock::Node>::iterator * iter,std::unique_ptr<Expression> * expr)243 bool BasicBlock::tryInsertExpression(std::vector<BasicBlock::Node>::iterator* iter,
244 std::unique_ptr<Expression>* expr) {
245 switch ((*expr)->fKind) {
246 case Expression::kBinary_Kind: {
247 BinaryExpression* b = (BinaryExpression*) expr->get();
248 if (!this->tryInsertExpression(iter, &b->fRight)) {
249 return false;
250 }
251 ++(*iter);
252 if (!this->tryInsertExpression(iter, &b->fLeft)) {
253 return false;
254 }
255 ++(*iter);
256 BasicBlock::Node node = { BasicBlock::Node::kExpression_Kind, true, expr, nullptr };
257 *iter = fNodes.insert(*iter, node);
258 return true;
259 }
260 case Expression::kBoolLiteral_Kind: // fall through
261 case Expression::kFloatLiteral_Kind: // fall through
262 case Expression::kIntLiteral_Kind: // fall through
263 case Expression::kVariableReference_Kind: {
264 BasicBlock::Node node = { BasicBlock::Node::kExpression_Kind, true, expr, nullptr };
265 *iter = fNodes.insert(*iter, node);
266 return true;
267 }
268 case Expression::kConstructor_Kind: {
269 Constructor* c = (Constructor*) expr->get();
270 for (auto& arg : c->fArguments) {
271 if (!this->tryInsertExpression(iter, &arg)) {
272 return false;
273 }
274 ++(*iter);
275 }
276 BasicBlock::Node node = { BasicBlock::Node::kExpression_Kind, true, expr, nullptr };
277 *iter = fNodes.insert(*iter, node);
278 return true;
279 }
280 default:
281 return false;
282 }
283 }
284
addExpression(CFG & cfg,std::unique_ptr<Expression> * e,bool constantPropagate)285 void CFGGenerator::addExpression(CFG& cfg, std::unique_ptr<Expression>* e, bool constantPropagate) {
286 ASSERT(e);
287 switch ((*e)->fKind) {
288 case Expression::kBinary_Kind: {
289 BinaryExpression* b = (BinaryExpression*) e->get();
290 switch (b->fOperator) {
291 case Token::LOGICALAND: // fall through
292 case Token::LOGICALOR: {
293 // this isn't as precise as it could be -- we don't bother to track that if we
294 // early exit from a logical and/or, we know which branch of an 'if' we're going
295 // to hit -- but it won't make much difference in practice.
296 this->addExpression(cfg, &b->fLeft, constantPropagate);
297 BlockId start = cfg.fCurrent;
298 cfg.newBlock();
299 this->addExpression(cfg, &b->fRight, constantPropagate);
300 cfg.newBlock();
301 cfg.addExit(start, cfg.fCurrent);
302 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({
303 BasicBlock::Node::kExpression_Kind,
304 constantPropagate,
305 e,
306 nullptr
307 });
308 break;
309 }
310 case Token::EQ: {
311 this->addExpression(cfg, &b->fRight, constantPropagate);
312 this->addLValue(cfg, &b->fLeft);
313 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({
314 BasicBlock::Node::kExpression_Kind,
315 constantPropagate,
316 e,
317 nullptr
318 });
319 break;
320 }
321 default:
322 this->addExpression(cfg, &b->fLeft, !Token::IsAssignment(b->fOperator));
323 this->addExpression(cfg, &b->fRight, constantPropagate);
324 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({
325 BasicBlock::Node::kExpression_Kind,
326 constantPropagate,
327 e,
328 nullptr
329 });
330 }
331 break;
332 }
333 case Expression::kConstructor_Kind: {
334 Constructor* c = (Constructor*) e->get();
335 for (auto& arg : c->fArguments) {
336 this->addExpression(cfg, &arg, constantPropagate);
337 }
338 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpression_Kind,
339 constantPropagate, e, nullptr });
340 break;
341 }
342 case Expression::kFunctionCall_Kind: {
343 FunctionCall* c = (FunctionCall*) e->get();
344 for (auto& arg : c->fArguments) {
345 this->addExpression(cfg, &arg, constantPropagate);
346 }
347 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpression_Kind,
348 constantPropagate, e, nullptr });
349 break;
350 }
351 case Expression::kFieldAccess_Kind:
352 this->addExpression(cfg, &((FieldAccess*) e->get())->fBase, constantPropagate);
353 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpression_Kind,
354 constantPropagate, e, nullptr });
355 break;
356 case Expression::kIndex_Kind:
357 this->addExpression(cfg, &((IndexExpression*) e->get())->fBase, constantPropagate);
358 this->addExpression(cfg, &((IndexExpression*) e->get())->fIndex, constantPropagate);
359 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpression_Kind,
360 constantPropagate, e, nullptr });
361 break;
362 case Expression::kPrefix_Kind: {
363 PrefixExpression* p = (PrefixExpression*) e->get();
364 this->addExpression(cfg, &p->fOperand, constantPropagate &&
365 p->fOperator != Token::PLUSPLUS &&
366 p->fOperator != Token::MINUSMINUS);
367 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpression_Kind,
368 constantPropagate, e, nullptr });
369 break;
370 }
371 case Expression::kPostfix_Kind:
372 this->addExpression(cfg, &((PostfixExpression*) e->get())->fOperand, false);
373 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpression_Kind,
374 constantPropagate, e, nullptr });
375 break;
376 case Expression::kSwizzle_Kind:
377 this->addExpression(cfg, &((Swizzle*) e->get())->fBase, constantPropagate);
378 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpression_Kind,
379 constantPropagate, e, nullptr });
380 break;
381 case Expression::kBoolLiteral_Kind: // fall through
382 case Expression::kFloatLiteral_Kind: // fall through
383 case Expression::kIntLiteral_Kind: // fall through
384 case Expression::kSetting_Kind: // fall through
385 case Expression::kVariableReference_Kind:
386 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpression_Kind,
387 constantPropagate, e, nullptr });
388 break;
389 case Expression::kTernary_Kind: {
390 TernaryExpression* t = (TernaryExpression*) e->get();
391 this->addExpression(cfg, &t->fTest, constantPropagate);
392 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpression_Kind,
393 constantPropagate, e, nullptr });
394 BlockId start = cfg.fCurrent;
395 cfg.newBlock();
396 this->addExpression(cfg, &t->fIfTrue, constantPropagate);
397 BlockId next = cfg.newBlock();
398 cfg.fCurrent = start;
399 cfg.newBlock();
400 this->addExpression(cfg, &t->fIfFalse, constantPropagate);
401 cfg.addExit(cfg.fCurrent, next);
402 cfg.fCurrent = next;
403 break;
404 }
405 case Expression::kFunctionReference_Kind: // fall through
406 case Expression::kTypeReference_Kind: // fall through
407 case Expression::kDefined_Kind:
408 ASSERT(false);
409 break;
410 }
411 }
412
413 // adds expressions that are evaluated as part of resolving an lvalue
addLValue(CFG & cfg,std::unique_ptr<Expression> * e)414 void CFGGenerator::addLValue(CFG& cfg, std::unique_ptr<Expression>* e) {
415 switch ((*e)->fKind) {
416 case Expression::kFieldAccess_Kind:
417 this->addLValue(cfg, &((FieldAccess&) **e).fBase);
418 break;
419 case Expression::kIndex_Kind:
420 this->addLValue(cfg, &((IndexExpression&) **e).fBase);
421 this->addExpression(cfg, &((IndexExpression&) **e).fIndex, true);
422 break;
423 case Expression::kSwizzle_Kind:
424 this->addLValue(cfg, &((Swizzle&) **e).fBase);
425 break;
426 case Expression::kVariableReference_Kind:
427 break;
428 default:
429 // not an lvalue, can't happen
430 ASSERT(false);
431 break;
432 }
433 }
434
addStatement(CFG & cfg,std::unique_ptr<Statement> * s)435 void CFGGenerator::addStatement(CFG& cfg, std::unique_ptr<Statement>* s) {
436 switch ((*s)->fKind) {
437 case Statement::kBlock_Kind:
438 for (auto& child : ((Block&) **s).fStatements) {
439 addStatement(cfg, &child);
440 }
441 break;
442 case Statement::kIf_Kind: {
443 IfStatement& ifs = (IfStatement&) **s;
444 this->addExpression(cfg, &ifs.fTest, true);
445 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kStatement_Kind, false,
446 nullptr, s });
447 BlockId start = cfg.fCurrent;
448 cfg.newBlock();
449 this->addStatement(cfg, &ifs.fIfTrue);
450 BlockId next = cfg.newBlock();
451 if (ifs.fIfFalse) {
452 cfg.fCurrent = start;
453 cfg.newBlock();
454 this->addStatement(cfg, &ifs.fIfFalse);
455 cfg.addExit(cfg.fCurrent, next);
456 cfg.fCurrent = next;
457 } else {
458 cfg.addExit(start, next);
459 }
460 break;
461 }
462 case Statement::kExpression_Kind: {
463 this->addExpression(cfg, &((ExpressionStatement&) **s).fExpression, true);
464 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kStatement_Kind, false,
465 nullptr, s });
466 break;
467 }
468 case Statement::kVarDeclarations_Kind: {
469 VarDeclarationsStatement& decls = ((VarDeclarationsStatement&) **s);
470 for (auto& stmt : decls.fDeclaration->fVars) {
471 if (stmt->fKind == Statement::kNop_Kind) {
472 continue;
473 }
474 VarDeclaration& vd = (VarDeclaration&) *stmt;
475 if (vd.fValue) {
476 this->addExpression(cfg, &vd.fValue, true);
477 }
478 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kStatement_Kind,
479 false, nullptr, &stmt });
480 }
481 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kStatement_Kind, false,
482 nullptr, s });
483 break;
484 }
485 case Statement::kDiscard_Kind:
486 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kStatement_Kind, false,
487 nullptr, s });
488 cfg.fCurrent = cfg.newIsolatedBlock();
489 break;
490 case Statement::kReturn_Kind: {
491 ReturnStatement& r = ((ReturnStatement&) **s);
492 if (r.fExpression) {
493 this->addExpression(cfg, &r.fExpression, true);
494 }
495 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kStatement_Kind, false,
496 nullptr, s });
497 cfg.fCurrent = cfg.newIsolatedBlock();
498 break;
499 }
500 case Statement::kBreak_Kind:
501 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kStatement_Kind, false,
502 nullptr, s });
503 cfg.addExit(cfg.fCurrent, fLoopExits.top());
504 cfg.fCurrent = cfg.newIsolatedBlock();
505 break;
506 case Statement::kContinue_Kind:
507 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kStatement_Kind, false,
508 nullptr, s });
509 cfg.addExit(cfg.fCurrent, fLoopContinues.top());
510 cfg.fCurrent = cfg.newIsolatedBlock();
511 break;
512 case Statement::kWhile_Kind: {
513 WhileStatement& w = (WhileStatement&) **s;
514 BlockId loopStart = cfg.newBlock();
515 fLoopContinues.push(loopStart);
516 BlockId loopExit = cfg.newIsolatedBlock();
517 fLoopExits.push(loopExit);
518 this->addExpression(cfg, &w.fTest, true);
519 BlockId test = cfg.fCurrent;
520 cfg.addExit(test, loopExit);
521 cfg.newBlock();
522 this->addStatement(cfg, &w.fStatement);
523 cfg.addExit(cfg.fCurrent, loopStart);
524 fLoopContinues.pop();
525 fLoopExits.pop();
526 cfg.fCurrent = loopExit;
527 break;
528 }
529 case Statement::kDo_Kind: {
530 DoStatement& d = (DoStatement&) **s;
531 BlockId loopStart = cfg.newBlock();
532 fLoopContinues.push(loopStart);
533 BlockId loopExit = cfg.newIsolatedBlock();
534 fLoopExits.push(loopExit);
535 this->addStatement(cfg, &d.fStatement);
536 this->addExpression(cfg, &d.fTest, true);
537 cfg.addExit(cfg.fCurrent, loopExit);
538 cfg.addExit(cfg.fCurrent, loopStart);
539 fLoopContinues.pop();
540 fLoopExits.pop();
541 cfg.fCurrent = loopExit;
542 break;
543 }
544 case Statement::kFor_Kind: {
545 ForStatement& f = (ForStatement&) **s;
546 if (f.fInitializer) {
547 this->addStatement(cfg, &f.fInitializer);
548 }
549 BlockId loopStart = cfg.newBlock();
550 BlockId next = cfg.newIsolatedBlock();
551 fLoopContinues.push(next);
552 BlockId loopExit = cfg.newIsolatedBlock();
553 fLoopExits.push(loopExit);
554 if (f.fTest) {
555 this->addExpression(cfg, &f.fTest, true);
556 // this isn't quite right; we should have an exit from here to the loop exit, and
557 // remove the exit from the loop body to the loop exit. Structuring it like this
558 // forces the optimizer to believe that the loop body is always executed at least
559 // once. While not strictly correct, this avoids incorrect "variable not assigned"
560 // errors on variables which are assigned within the loop. The correct solution to
561 // this is to analyze the loop to see whether or not at least one iteration is
562 // guaranteed to happen, but for the time being we take the easy way out.
563 }
564 cfg.newBlock();
565 this->addStatement(cfg, &f.fStatement);
566 cfg.addExit(cfg.fCurrent, next);
567 cfg.fCurrent = next;
568 if (f.fNext) {
569 this->addExpression(cfg, &f.fNext, true);
570 }
571 cfg.addExit(cfg.fCurrent, loopStart);
572 cfg.addExit(cfg.fCurrent, loopExit);
573 fLoopContinues.pop();
574 fLoopExits.pop();
575 cfg.fCurrent = loopExit;
576 break;
577 }
578 case Statement::kSwitch_Kind: {
579 SwitchStatement& ss = (SwitchStatement&) **s;
580 this->addExpression(cfg, &ss.fValue, true);
581 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kStatement_Kind, false,
582 nullptr, s });
583 BlockId start = cfg.fCurrent;
584 BlockId switchExit = cfg.newIsolatedBlock();
585 fLoopExits.push(switchExit);
586 for (const auto& c : ss.fCases) {
587 cfg.newBlock();
588 cfg.addExit(start, cfg.fCurrent);
589 if (c->fValue) {
590 // technically this should go in the start block, but it doesn't actually matter
591 // because it must be constant. Not worth running two loops for.
592 this->addExpression(cfg, &c->fValue, true);
593 }
594 for (auto& caseStatement : c->fStatements) {
595 this->addStatement(cfg, &caseStatement);
596 }
597 }
598 cfg.addExit(cfg.fCurrent, switchExit);
599 // note that unlike GLSL, our grammar requires the default case to be last
600 if (0 == ss.fCases.size() || ss.fCases[ss.fCases.size() - 1]->fValue) {
601 // switch does not have a default clause, mark that it can skip straight to the end
602 cfg.addExit(start, switchExit);
603 }
604 fLoopExits.pop();
605 cfg.fCurrent = switchExit;
606 break;
607 }
608 case Statement::kNop_Kind:
609 break;
610 default:
611 printf("statement: %s\n", (*s)->description().c_str());
612 ABORT("unsupported statement kind");
613 }
614 }
615
getCFG(FunctionDefinition & f)616 CFG CFGGenerator::getCFG(FunctionDefinition& f) {
617 CFG result;
618 result.fStart = result.newBlock();
619 result.fCurrent = result.fStart;
620 this->addStatement(result, &f.fBody);
621 result.newBlock();
622 result.fExit = result.fCurrent;
623 return result;
624 }
625
626 } // namespace
627