SkSLCFGGenerator.cpp revision ccf59917d3fe7aaf59de714acfbd0596503f324f
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
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++) {
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
85bool 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
126bool 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
145bool 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
243bool 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
285void 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
414void 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
435void 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
616CFG 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