• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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