blob: a4397f3f3313dff9fd8ec0f0b79e58161bd72779 [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
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "src/sksl/SkSLCFGGenerator.h"
ethannicholas22f939e2016-10-13 13:25:34 -07009
Mike Kleinc0bd9f92019-04-23 12:05:21 -050010#include "src/sksl/ir/SkSLBinaryExpression.h"
11#include "src/sksl/ir/SkSLConstructor.h"
12#include "src/sksl/ir/SkSLDoStatement.h"
13#include "src/sksl/ir/SkSLExpressionStatement.h"
14#include "src/sksl/ir/SkSLFieldAccess.h"
15#include "src/sksl/ir/SkSLForStatement.h"
16#include "src/sksl/ir/SkSLFunctionCall.h"
17#include "src/sksl/ir/SkSLIfStatement.h"
18#include "src/sksl/ir/SkSLIndexExpression.h"
19#include "src/sksl/ir/SkSLPostfixExpression.h"
20#include "src/sksl/ir/SkSLPrefixExpression.h"
21#include "src/sksl/ir/SkSLReturnStatement.h"
22#include "src/sksl/ir/SkSLSwitchStatement.h"
23#include "src/sksl/ir/SkSLSwizzle.h"
24#include "src/sksl/ir/SkSLTernaryExpression.h"
25#include "src/sksl/ir/SkSLVarDeclarationsStatement.h"
26#include "src/sksl/ir/SkSLWhileStatement.h"
ethannicholas22f939e2016-10-13 13:25:34 -070027
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) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -040092 SkASSERT((*iter)->expression()->get() != e);
Ethan Nicholascb670962017-04-20 19:31:52 -040093 Expression* old = (*iter)->expression()->get();
94 do {
95 if ((*iter) == fNodes.begin()) {
Ethan Nicholas4b330df2017-05-17 10:52:55 -040096 return false;
Ethan Nicholascb670962017-04-20 19:31:52 -040097 }
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) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400104 SkASSERT(*iter != fNodes.end());
Ethan Nicholascb670962017-04-20 19:31:52 -0400105 ++(*iter);
106 }
107 } else {
108 Statement* old = (*iter)->statement()->get();
109 do {
110 if ((*iter) == fNodes.begin()) {
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400111 return false;
Ethan Nicholascb670962017-04-20 19:31:52 -0400112 }
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) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400119 SkASSERT(*iter != fNodes.end());
Ethan Nicholascb670962017-04-20 19:31:52 -0400120 ++(*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());
Ethan Nicholasa583b812018-01-18 13:32:11 -0500140 case Expression::kTernary_Kind:
141 if (!this->tryRemoveExpressionBefore(iter,
142 ((TernaryExpression*) lvalue)->fTest.get())) {
143 return false;
144 }
145 if (!this->tryRemoveLValueBefore(iter, ((TernaryExpression*) lvalue)->fIfTrue.get())) {
146 return false;
147 }
148 return this->tryRemoveLValueBefore(iter, ((TernaryExpression*) lvalue)->fIfFalse.get());
Ethan Nicholascb670962017-04-20 19:31:52 -0400149 default:
150 ABORT("invalid lvalue: %s\n", lvalue->description().c_str());
151 }
152}
153
154bool BasicBlock::tryRemoveExpression(std::vector<BasicBlock::Node>::iterator* iter) {
155 Expression* expr = (*iter)->expression()->get();
156 switch (expr->fKind) {
157 case Expression::kBinary_Kind: {
158 BinaryExpression* b = (BinaryExpression*) expr;
159 if (b->fOperator == Token::EQ) {
160 if (!this->tryRemoveLValueBefore(iter, b->fLeft.get())) {
161 return false;
162 }
163 } else if (!this->tryRemoveExpressionBefore(iter, b->fLeft.get())) {
164 return false;
165 }
166 if (!this->tryRemoveExpressionBefore(iter, b->fRight.get())) {
167 return false;
168 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400169 SkASSERT((*iter)->expression()->get() == expr);
Ethan Nicholascb670962017-04-20 19:31:52 -0400170 *iter = fNodes.erase(*iter);
171 return true;
172 }
173 case Expression::kTernary_Kind: {
174 // ternaries cross basic block boundaries, must regenerate the CFG to remove it
175 return false;
176 }
177 case Expression::kFieldAccess_Kind: {
178 FieldAccess* f = (FieldAccess*) expr;
179 if (!this->tryRemoveExpressionBefore(iter, f->fBase.get())) {
180 return false;
181 }
182 *iter = fNodes.erase(*iter);
183 return true;
184 }
185 case Expression::kSwizzle_Kind: {
186 Swizzle* s = (Swizzle*) expr;
187 if (!this->tryRemoveExpressionBefore(iter, s->fBase.get())) {
188 return false;
189 }
190 *iter = fNodes.erase(*iter);
191 return true;
192 }
193 case Expression::kIndex_Kind: {
194 IndexExpression* idx = (IndexExpression*) expr;
195 if (!this->tryRemoveExpressionBefore(iter, idx->fBase.get())) {
196 return false;
197 }
198 if (!this->tryRemoveExpressionBefore(iter, idx->fIndex.get())) {
199 return false;
200 }
201 *iter = fNodes.erase(*iter);
202 return true;
203 }
204 case Expression::kConstructor_Kind: {
205 Constructor* c = (Constructor*) expr;
206 for (auto& arg : c->fArguments) {
207 if (!this->tryRemoveExpressionBefore(iter, arg.get())) {
208 return false;
209 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400210 SkASSERT((*iter)->expression()->get() == expr);
Ethan Nicholascb670962017-04-20 19:31:52 -0400211 }
212 *iter = fNodes.erase(*iter);
213 return true;
214 }
215 case Expression::kFunctionCall_Kind: {
216 FunctionCall* f = (FunctionCall*) expr;
217 for (auto& arg : f->fArguments) {
218 if (!this->tryRemoveExpressionBefore(iter, arg.get())) {
219 return false;
220 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400221 SkASSERT((*iter)->expression()->get() == expr);
Ethan Nicholascb670962017-04-20 19:31:52 -0400222 }
223 *iter = fNodes.erase(*iter);
224 return true;
225 }
226 case Expression::kPrefix_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::kPostfix_Kind:
234 if (!this->tryRemoveExpressionBefore(iter,
235 ((PrefixExpression*) expr)->fOperand.get())) {
236 return false;
237 }
238 *iter = fNodes.erase(*iter);
239 return true;
240 case Expression::kBoolLiteral_Kind: // fall through
241 case Expression::kFloatLiteral_Kind: // fall through
242 case Expression::kIntLiteral_Kind: // fall through
Ethan Nicholas762466e2017-06-29 10:03:38 -0400243 case Expression::kSetting_Kind: // fall through
Ethan Nicholascb670962017-04-20 19:31:52 -0400244 case Expression::kVariableReference_Kind:
245 *iter = fNodes.erase(*iter);
246 return true;
247 default:
248 ABORT("unhandled expression: %s\n", expr->description().c_str());
249 }
250}
251
252bool BasicBlock::tryInsertExpression(std::vector<BasicBlock::Node>::iterator* iter,
253 std::unique_ptr<Expression>* expr) {
254 switch ((*expr)->fKind) {
255 case Expression::kBinary_Kind: {
256 BinaryExpression* b = (BinaryExpression*) expr->get();
257 if (!this->tryInsertExpression(iter, &b->fRight)) {
258 return false;
259 }
260 ++(*iter);
261 if (!this->tryInsertExpression(iter, &b->fLeft)) {
262 return false;
263 }
264 ++(*iter);
265 BasicBlock::Node node = { BasicBlock::Node::kExpression_Kind, true, expr, nullptr };
266 *iter = fNodes.insert(*iter, node);
267 return true;
268 }
269 case Expression::kBoolLiteral_Kind: // fall through
270 case Expression::kFloatLiteral_Kind: // fall through
271 case Expression::kIntLiteral_Kind: // fall through
272 case Expression::kVariableReference_Kind: {
273 BasicBlock::Node node = { BasicBlock::Node::kExpression_Kind, true, expr, nullptr };
274 *iter = fNodes.insert(*iter, node);
275 return true;
276 }
277 case Expression::kConstructor_Kind: {
278 Constructor* c = (Constructor*) expr->get();
279 for (auto& arg : c->fArguments) {
280 if (!this->tryInsertExpression(iter, &arg)) {
281 return false;
282 }
283 ++(*iter);
284 }
285 BasicBlock::Node node = { BasicBlock::Node::kExpression_Kind, true, expr, nullptr };
286 *iter = fNodes.insert(*iter, node);
287 return true;
288 }
289 default:
290 return false;
291 }
292}
293
Ethan Nicholas86a43402017-01-19 13:32:00 -0500294void CFGGenerator::addExpression(CFG& cfg, std::unique_ptr<Expression>* e, bool constantPropagate) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400295 SkASSERT(e);
Ethan Nicholas86a43402017-01-19 13:32:00 -0500296 switch ((*e)->fKind) {
ethannicholas22f939e2016-10-13 13:25:34 -0700297 case Expression::kBinary_Kind: {
Ethan Nicholas86a43402017-01-19 13:32:00 -0500298 BinaryExpression* b = (BinaryExpression*) e->get();
ethannicholas22f939e2016-10-13 13:25:34 -0700299 switch (b->fOperator) {
300 case Token::LOGICALAND: // fall through
301 case Token::LOGICALOR: {
302 // this isn't as precise as it could be -- we don't bother to track that if we
303 // early exit from a logical and/or, we know which branch of an 'if' we're going
304 // to hit -- but it won't make much difference in practice.
Ethan Nicholas86a43402017-01-19 13:32:00 -0500305 this->addExpression(cfg, &b->fLeft, constantPropagate);
ethannicholas22f939e2016-10-13 13:25:34 -0700306 BlockId start = cfg.fCurrent;
307 cfg.newBlock();
Ethan Nicholas86a43402017-01-19 13:32:00 -0500308 this->addExpression(cfg, &b->fRight, constantPropagate);
ethannicholas22f939e2016-10-13 13:25:34 -0700309 cfg.newBlock();
310 cfg.addExit(start, cfg.fCurrent);
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400311 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({
312 BasicBlock::Node::kExpression_Kind,
313 constantPropagate,
314 e,
315 nullptr
316 });
ethannicholas22f939e2016-10-13 13:25:34 -0700317 break;
318 }
319 case Token::EQ: {
Ethan Nicholas86a43402017-01-19 13:32:00 -0500320 this->addExpression(cfg, &b->fRight, constantPropagate);
321 this->addLValue(cfg, &b->fLeft);
322 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({
323 BasicBlock::Node::kExpression_Kind,
324 constantPropagate,
325 e,
326 nullptr
ethannicholas22f939e2016-10-13 13:25:34 -0700327 });
328 break;
329 }
330 default:
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700331 this->addExpression(cfg, &b->fLeft, !Compiler::IsAssignment(b->fOperator));
Ethan Nicholas86a43402017-01-19 13:32:00 -0500332 this->addExpression(cfg, &b->fRight, constantPropagate);
333 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({
334 BasicBlock::Node::kExpression_Kind,
335 constantPropagate,
336 e,
337 nullptr
ethannicholas22f939e2016-10-13 13:25:34 -0700338 });
339 }
340 break;
341 }
342 case Expression::kConstructor_Kind: {
Ethan Nicholas86a43402017-01-19 13:32:00 -0500343 Constructor* c = (Constructor*) e->get();
344 for (auto& arg : c->fArguments) {
345 this->addExpression(cfg, &arg, constantPropagate);
ethannicholas22f939e2016-10-13 13:25:34 -0700346 }
Ethan Nicholas86a43402017-01-19 13:32:00 -0500347 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpression_Kind,
348 constantPropagate, e, nullptr });
ethannicholas22f939e2016-10-13 13:25:34 -0700349 break;
350 }
351 case Expression::kFunctionCall_Kind: {
Ethan Nicholas86a43402017-01-19 13:32:00 -0500352 FunctionCall* c = (FunctionCall*) e->get();
353 for (auto& arg : c->fArguments) {
354 this->addExpression(cfg, &arg, constantPropagate);
ethannicholas22f939e2016-10-13 13:25:34 -0700355 }
Ethan Nicholas86a43402017-01-19 13:32:00 -0500356 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpression_Kind,
357 constantPropagate, e, nullptr });
ethannicholas22f939e2016-10-13 13:25:34 -0700358 break;
359 }
360 case Expression::kFieldAccess_Kind:
Ethan Nicholas86a43402017-01-19 13:32:00 -0500361 this->addExpression(cfg, &((FieldAccess*) e->get())->fBase, constantPropagate);
362 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpression_Kind,
363 constantPropagate, e, nullptr });
ethannicholas22f939e2016-10-13 13:25:34 -0700364 break;
365 case Expression::kIndex_Kind:
Ethan Nicholas86a43402017-01-19 13:32:00 -0500366 this->addExpression(cfg, &((IndexExpression*) e->get())->fBase, constantPropagate);
367 this->addExpression(cfg, &((IndexExpression*) e->get())->fIndex, constantPropagate);
368 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpression_Kind,
369 constantPropagate, e, nullptr });
ethannicholas22f939e2016-10-13 13:25:34 -0700370 break;
Ethan Nicholasaf197692017-02-27 13:26:45 -0500371 case Expression::kPrefix_Kind: {
372 PrefixExpression* p = (PrefixExpression*) e->get();
373 this->addExpression(cfg, &p->fOperand, constantPropagate &&
374 p->fOperator != Token::PLUSPLUS &&
375 p->fOperator != Token::MINUSMINUS);
Ethan Nicholas86a43402017-01-19 13:32:00 -0500376 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpression_Kind,
377 constantPropagate, e, nullptr });
ethannicholas22f939e2016-10-13 13:25:34 -0700378 break;
Ethan Nicholasaf197692017-02-27 13:26:45 -0500379 }
ethannicholas22f939e2016-10-13 13:25:34 -0700380 case Expression::kPostfix_Kind:
Ethan Nicholasaf197692017-02-27 13:26:45 -0500381 this->addExpression(cfg, &((PostfixExpression*) e->get())->fOperand, false);
Ethan Nicholas86a43402017-01-19 13:32:00 -0500382 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpression_Kind,
383 constantPropagate, e, nullptr });
ethannicholas22f939e2016-10-13 13:25:34 -0700384 break;
385 case Expression::kSwizzle_Kind:
Ethan Nicholas86a43402017-01-19 13:32:00 -0500386 this->addExpression(cfg, &((Swizzle*) e->get())->fBase, constantPropagate);
387 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpression_Kind,
388 constantPropagate, e, nullptr });
ethannicholas22f939e2016-10-13 13:25:34 -0700389 break;
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400390 case Expression::kAppendStage_Kind: // fall through
ethannicholas22f939e2016-10-13 13:25:34 -0700391 case Expression::kBoolLiteral_Kind: // fall through
392 case Expression::kFloatLiteral_Kind: // fall through
393 case Expression::kIntLiteral_Kind: // fall through
Ethan Nicholasee1c8a72019-02-22 10:50:47 -0500394 case Expression::kNullLiteral_Kind: // fall through
Ethan Nicholas762466e2017-06-29 10:03:38 -0400395 case Expression::kSetting_Kind: // fall through
ethannicholas22f939e2016-10-13 13:25:34 -0700396 case Expression::kVariableReference_Kind:
Ethan Nicholas86a43402017-01-19 13:32:00 -0500397 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpression_Kind,
398 constantPropagate, e, nullptr });
ethannicholas22f939e2016-10-13 13:25:34 -0700399 break;
400 case Expression::kTernary_Kind: {
Ethan Nicholas86a43402017-01-19 13:32:00 -0500401 TernaryExpression* t = (TernaryExpression*) e->get();
402 this->addExpression(cfg, &t->fTest, constantPropagate);
Ethan Nicholascb670962017-04-20 19:31:52 -0400403 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpression_Kind,
404 constantPropagate, e, nullptr });
ethannicholas22f939e2016-10-13 13:25:34 -0700405 BlockId start = cfg.fCurrent;
406 cfg.newBlock();
Ethan Nicholas86a43402017-01-19 13:32:00 -0500407 this->addExpression(cfg, &t->fIfTrue, constantPropagate);
ethannicholas22f939e2016-10-13 13:25:34 -0700408 BlockId next = cfg.newBlock();
409 cfg.fCurrent = start;
410 cfg.newBlock();
Ethan Nicholas86a43402017-01-19 13:32:00 -0500411 this->addExpression(cfg, &t->fIfFalse, constantPropagate);
ethannicholas22f939e2016-10-13 13:25:34 -0700412 cfg.addExit(cfg.fCurrent, next);
413 cfg.fCurrent = next;
414 break;
415 }
416 case Expression::kFunctionReference_Kind: // fall through
417 case Expression::kTypeReference_Kind: // fall through
418 case Expression::kDefined_Kind:
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400419 SkASSERT(false);
ethannicholas22f939e2016-10-13 13:25:34 -0700420 break;
421 }
422}
423
424// adds expressions that are evaluated as part of resolving an lvalue
Ethan Nicholas86a43402017-01-19 13:32:00 -0500425void CFGGenerator::addLValue(CFG& cfg, std::unique_ptr<Expression>* e) {
426 switch ((*e)->fKind) {
ethannicholas22f939e2016-10-13 13:25:34 -0700427 case Expression::kFieldAccess_Kind:
Ethan Nicholas86a43402017-01-19 13:32:00 -0500428 this->addLValue(cfg, &((FieldAccess&) **e).fBase);
ethannicholas22f939e2016-10-13 13:25:34 -0700429 break;
430 case Expression::kIndex_Kind:
Ethan Nicholas86a43402017-01-19 13:32:00 -0500431 this->addLValue(cfg, &((IndexExpression&) **e).fBase);
432 this->addExpression(cfg, &((IndexExpression&) **e).fIndex, true);
ethannicholas22f939e2016-10-13 13:25:34 -0700433 break;
434 case Expression::kSwizzle_Kind:
Ethan Nicholas86a43402017-01-19 13:32:00 -0500435 this->addLValue(cfg, &((Swizzle&) **e).fBase);
ethannicholas22f939e2016-10-13 13:25:34 -0700436 break;
437 case Expression::kVariableReference_Kind:
438 break;
Ethan Nicholasa583b812018-01-18 13:32:11 -0500439 case Expression::kTernary_Kind:
440 this->addExpression(cfg, &((TernaryExpression&) **e).fTest, true);
441 // Technically we will of course only evaluate one or the other, but if the test turns
442 // out to be constant, the ternary will get collapsed down to just one branch anyway. So
443 // it should be ok to pretend that we always evaluate both branches here.
444 this->addLValue(cfg, &((TernaryExpression&) **e).fIfTrue);
445 this->addLValue(cfg, &((TernaryExpression&) **e).fIfFalse);
446 break;
ethannicholas22f939e2016-10-13 13:25:34 -0700447 default:
448 // not an lvalue, can't happen
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400449 SkASSERT(false);
ethannicholas22f939e2016-10-13 13:25:34 -0700450 break;
451 }
452}
453
Ethan Nicholas0d997662019-04-08 09:46:01 -0400454static bool is_true(Expression& expr) {
455 return expr.fKind == Expression::kBoolLiteral_Kind && ((BoolLiteral&) expr).fValue;
456}
457
Ethan Nicholascb670962017-04-20 19:31:52 -0400458void CFGGenerator::addStatement(CFG& cfg, std::unique_ptr<Statement>* s) {
459 switch ((*s)->fKind) {
ethannicholas22f939e2016-10-13 13:25:34 -0700460 case Statement::kBlock_Kind:
Ethan Nicholascb670962017-04-20 19:31:52 -0400461 for (auto& child : ((Block&) **s).fStatements) {
462 addStatement(cfg, &child);
ethannicholas22f939e2016-10-13 13:25:34 -0700463 }
464 break;
465 case Statement::kIf_Kind: {
Ethan Nicholascb670962017-04-20 19:31:52 -0400466 IfStatement& ifs = (IfStatement&) **s;
467 this->addExpression(cfg, &ifs.fTest, true);
468 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kStatement_Kind, false,
469 nullptr, s });
ethannicholas22f939e2016-10-13 13:25:34 -0700470 BlockId start = cfg.fCurrent;
471 cfg.newBlock();
Ethan Nicholascb670962017-04-20 19:31:52 -0400472 this->addStatement(cfg, &ifs.fIfTrue);
ethannicholas22f939e2016-10-13 13:25:34 -0700473 BlockId next = cfg.newBlock();
Ethan Nicholascb670962017-04-20 19:31:52 -0400474 if (ifs.fIfFalse) {
ethannicholas22f939e2016-10-13 13:25:34 -0700475 cfg.fCurrent = start;
476 cfg.newBlock();
Ethan Nicholascb670962017-04-20 19:31:52 -0400477 this->addStatement(cfg, &ifs.fIfFalse);
ethannicholas22f939e2016-10-13 13:25:34 -0700478 cfg.addExit(cfg.fCurrent, next);
479 cfg.fCurrent = next;
480 } else {
481 cfg.addExit(start, next);
482 }
483 break;
484 }
485 case Statement::kExpression_Kind: {
Ethan Nicholascb670962017-04-20 19:31:52 -0400486 this->addExpression(cfg, &((ExpressionStatement&) **s).fExpression, true);
487 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kStatement_Kind, false,
488 nullptr, s });
ethannicholas22f939e2016-10-13 13:25:34 -0700489 break;
490 }
491 case Statement::kVarDeclarations_Kind: {
Ethan Nicholas82a62d22017-11-07 14:42:10 +0000492 VarDeclarationsStatement& decls = ((VarDeclarationsStatement&) **s);
493 for (auto& stmt : decls.fDeclaration->fVars) {
494 if (stmt->fKind == Statement::kNop_Kind) {
495 continue;
496 }
497 VarDeclaration& vd = (VarDeclaration&) *stmt;
498 if (vd.fValue) {
499 this->addExpression(cfg, &vd.fValue, true);
500 }
501 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kStatement_Kind,
502 false, nullptr, &stmt });
503 }
Ethan Nicholas91a10532017-06-22 11:24:38 -0400504 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kStatement_Kind, false,
505 nullptr, s });
ethannicholas22f939e2016-10-13 13:25:34 -0700506 break;
507 }
508 case Statement::kDiscard_Kind:
Ethan Nicholas86a43402017-01-19 13:32:00 -0500509 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kStatement_Kind, false,
510 nullptr, s });
ethannicholas22f939e2016-10-13 13:25:34 -0700511 cfg.fCurrent = cfg.newIsolatedBlock();
512 break;
513 case Statement::kReturn_Kind: {
Ethan Nicholascb670962017-04-20 19:31:52 -0400514 ReturnStatement& r = ((ReturnStatement&) **s);
ethannicholas22f939e2016-10-13 13:25:34 -0700515 if (r.fExpression) {
Ethan Nicholas86a43402017-01-19 13:32:00 -0500516 this->addExpression(cfg, &r.fExpression, true);
ethannicholas22f939e2016-10-13 13:25:34 -0700517 }
Ethan Nicholas86a43402017-01-19 13:32:00 -0500518 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kStatement_Kind, false,
519 nullptr, s });
ethannicholas22f939e2016-10-13 13:25:34 -0700520 cfg.fCurrent = cfg.newIsolatedBlock();
521 break;
522 }
523 case Statement::kBreak_Kind:
Ethan Nicholas86a43402017-01-19 13:32:00 -0500524 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kStatement_Kind, false,
525 nullptr, s });
ethannicholas22f939e2016-10-13 13:25:34 -0700526 cfg.addExit(cfg.fCurrent, fLoopExits.top());
527 cfg.fCurrent = cfg.newIsolatedBlock();
528 break;
529 case Statement::kContinue_Kind:
Ethan Nicholas86a43402017-01-19 13:32:00 -0500530 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kStatement_Kind, false,
531 nullptr, s });
ethannicholas22f939e2016-10-13 13:25:34 -0700532 cfg.addExit(cfg.fCurrent, fLoopContinues.top());
533 cfg.fCurrent = cfg.newIsolatedBlock();
534 break;
535 case Statement::kWhile_Kind: {
Ethan Nicholascb670962017-04-20 19:31:52 -0400536 WhileStatement& w = (WhileStatement&) **s;
ethannicholas22f939e2016-10-13 13:25:34 -0700537 BlockId loopStart = cfg.newBlock();
538 fLoopContinues.push(loopStart);
539 BlockId loopExit = cfg.newIsolatedBlock();
540 fLoopExits.push(loopExit);
Ethan Nicholascb670962017-04-20 19:31:52 -0400541 this->addExpression(cfg, &w.fTest, true);
ethannicholas22f939e2016-10-13 13:25:34 -0700542 BlockId test = cfg.fCurrent;
Ethan Nicholas0d997662019-04-08 09:46:01 -0400543 if (!is_true(*w.fTest)) {
544 cfg.addExit(test, loopExit);
545 }
ethannicholas22f939e2016-10-13 13:25:34 -0700546 cfg.newBlock();
Ethan Nicholascb670962017-04-20 19:31:52 -0400547 this->addStatement(cfg, &w.fStatement);
ethannicholas22f939e2016-10-13 13:25:34 -0700548 cfg.addExit(cfg.fCurrent, loopStart);
549 fLoopContinues.pop();
550 fLoopExits.pop();
551 cfg.fCurrent = loopExit;
552 break;
553 }
554 case Statement::kDo_Kind: {
Ethan Nicholascb670962017-04-20 19:31:52 -0400555 DoStatement& d = (DoStatement&) **s;
ethannicholas22f939e2016-10-13 13:25:34 -0700556 BlockId loopStart = cfg.newBlock();
557 fLoopContinues.push(loopStart);
558 BlockId loopExit = cfg.newIsolatedBlock();
559 fLoopExits.push(loopExit);
Ethan Nicholascb670962017-04-20 19:31:52 -0400560 this->addStatement(cfg, &d.fStatement);
561 this->addExpression(cfg, &d.fTest, true);
ethannicholas22f939e2016-10-13 13:25:34 -0700562 cfg.addExit(cfg.fCurrent, loopExit);
563 cfg.addExit(cfg.fCurrent, loopStart);
564 fLoopContinues.pop();
565 fLoopExits.pop();
566 cfg.fCurrent = loopExit;
567 break;
568 }
569 case Statement::kFor_Kind: {
Ethan Nicholascb670962017-04-20 19:31:52 -0400570 ForStatement& f = (ForStatement&) **s;
571 if (f.fInitializer) {
572 this->addStatement(cfg, &f.fInitializer);
ethannicholas22f939e2016-10-13 13:25:34 -0700573 }
574 BlockId loopStart = cfg.newBlock();
575 BlockId next = cfg.newIsolatedBlock();
576 fLoopContinues.push(next);
577 BlockId loopExit = cfg.newIsolatedBlock();
578 fLoopExits.push(loopExit);
Ethan Nicholascb670962017-04-20 19:31:52 -0400579 if (f.fTest) {
580 this->addExpression(cfg, &f.fTest, true);
Ethan Nicholasd9fe7002017-05-30 10:15:34 -0400581 // this isn't quite right; we should have an exit from here to the loop exit, and
582 // remove the exit from the loop body to the loop exit. Structuring it like this
583 // forces the optimizer to believe that the loop body is always executed at least
584 // once. While not strictly correct, this avoids incorrect "variable not assigned"
585 // errors on variables which are assigned within the loop. The correct solution to
586 // this is to analyze the loop to see whether or not at least one iteration is
587 // guaranteed to happen, but for the time being we take the easy way out.
ethannicholas22f939e2016-10-13 13:25:34 -0700588 }
589 cfg.newBlock();
Ethan Nicholascb670962017-04-20 19:31:52 -0400590 this->addStatement(cfg, &f.fStatement);
ethannicholas22f939e2016-10-13 13:25:34 -0700591 cfg.addExit(cfg.fCurrent, next);
592 cfg.fCurrent = next;
Ethan Nicholascb670962017-04-20 19:31:52 -0400593 if (f.fNext) {
594 this->addExpression(cfg, &f.fNext, true);
ethannicholas22f939e2016-10-13 13:25:34 -0700595 }
Ethan Nicholas86a43402017-01-19 13:32:00 -0500596 cfg.addExit(cfg.fCurrent, loopStart);
Ethan Nicholasd9fe7002017-05-30 10:15:34 -0400597 cfg.addExit(cfg.fCurrent, loopExit);
ethannicholas22f939e2016-10-13 13:25:34 -0700598 fLoopContinues.pop();
599 fLoopExits.pop();
600 cfg.fCurrent = loopExit;
601 break;
602 }
Ethan Nicholasaf197692017-02-27 13:26:45 -0500603 case Statement::kSwitch_Kind: {
Ethan Nicholascb670962017-04-20 19:31:52 -0400604 SwitchStatement& ss = (SwitchStatement&) **s;
605 this->addExpression(cfg, &ss.fValue, true);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -0400606 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kStatement_Kind, false,
607 nullptr, s });
Ethan Nicholasaf197692017-02-27 13:26:45 -0500608 BlockId start = cfg.fCurrent;
609 BlockId switchExit = cfg.newIsolatedBlock();
610 fLoopExits.push(switchExit);
Ethan Nicholascb670962017-04-20 19:31:52 -0400611 for (const auto& c : ss.fCases) {
Ethan Nicholasaf197692017-02-27 13:26:45 -0500612 cfg.newBlock();
613 cfg.addExit(start, cfg.fCurrent);
Ethan Nicholaseace9352018-10-15 20:09:54 +0000614 if (c->fValue) {
615 // technically this should go in the start block, but it doesn't actually matter
616 // because it must be constant. Not worth running two loops for.
617 this->addExpression(cfg, &c->fValue, true);
618 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400619 for (auto& caseStatement : c->fStatements) {
620 this->addStatement(cfg, &caseStatement);
Ethan Nicholasaf197692017-02-27 13:26:45 -0500621 }
622 }
623 cfg.addExit(cfg.fCurrent, switchExit);
624 // note that unlike GLSL, our grammar requires the default case to be last
Ethan Nicholascb670962017-04-20 19:31:52 -0400625 if (0 == ss.fCases.size() || ss.fCases[ss.fCases.size() - 1]->fValue) {
Ethan Nicholasaf197692017-02-27 13:26:45 -0500626 // switch does not have a default clause, mark that it can skip straight to the end
627 cfg.addExit(start, switchExit);
628 }
629 fLoopExits.pop();
630 cfg.fCurrent = switchExit;
631 break;
632 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400633 case Statement::kNop_Kind:
634 break;
ethannicholas22f939e2016-10-13 13:25:34 -0700635 default:
Ethan Nicholascb670962017-04-20 19:31:52 -0400636 printf("statement: %s\n", (*s)->description().c_str());
ethannicholas22f939e2016-10-13 13:25:34 -0700637 ABORT("unsupported statement kind");
638 }
639}
640
Ethan Nicholascb670962017-04-20 19:31:52 -0400641CFG CFGGenerator::getCFG(FunctionDefinition& f) {
ethannicholas22f939e2016-10-13 13:25:34 -0700642 CFG result;
643 result.fStart = result.newBlock();
644 result.fCurrent = result.fStart;
Ethan Nicholascb670962017-04-20 19:31:52 -0400645 this->addStatement(result, &f.fBody);
ethannicholas22f939e2016-10-13 13:25:34 -0700646 result.newBlock();
647 result.fExit = result.fCurrent;
648 return result;
649}
650
651} // namespace