blob: 9271aa198a754db425eb94724c12bedddcc1deb7 [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) {
Ethan Nicholas91164d12019-05-15 15:29:54 -0400129 case Expression::kExternalValue_Kind: // fall through
Ethan Nicholascb670962017-04-20 19:31:52 -0400130 case Expression::kVariableReference_Kind:
131 return true;
132 case Expression::kSwizzle_Kind:
133 return this->tryRemoveLValueBefore(iter, ((Swizzle*) lvalue)->fBase.get());
134 case Expression::kFieldAccess_Kind:
135 return this->tryRemoveLValueBefore(iter, ((FieldAccess*) lvalue)->fBase.get());
136 case Expression::kIndex_Kind:
137 if (!this->tryRemoveLValueBefore(iter, ((IndexExpression*) lvalue)->fBase.get())) {
138 return false;
139 }
140 return this->tryRemoveExpressionBefore(iter, ((IndexExpression*) lvalue)->fIndex.get());
Ethan Nicholasa583b812018-01-18 13:32:11 -0500141 case Expression::kTernary_Kind:
142 if (!this->tryRemoveExpressionBefore(iter,
143 ((TernaryExpression*) lvalue)->fTest.get())) {
144 return false;
145 }
146 if (!this->tryRemoveLValueBefore(iter, ((TernaryExpression*) lvalue)->fIfTrue.get())) {
147 return false;
148 }
149 return this->tryRemoveLValueBefore(iter, ((TernaryExpression*) lvalue)->fIfFalse.get());
Ethan Nicholascb670962017-04-20 19:31:52 -0400150 default:
151 ABORT("invalid lvalue: %s\n", lvalue->description().c_str());
152 }
153}
154
155bool BasicBlock::tryRemoveExpression(std::vector<BasicBlock::Node>::iterator* iter) {
156 Expression* expr = (*iter)->expression()->get();
157 switch (expr->fKind) {
158 case Expression::kBinary_Kind: {
159 BinaryExpression* b = (BinaryExpression*) expr;
160 if (b->fOperator == Token::EQ) {
161 if (!this->tryRemoveLValueBefore(iter, b->fLeft.get())) {
162 return false;
163 }
164 } else if (!this->tryRemoveExpressionBefore(iter, b->fLeft.get())) {
165 return false;
166 }
167 if (!this->tryRemoveExpressionBefore(iter, b->fRight.get())) {
168 return false;
169 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400170 SkASSERT((*iter)->expression()->get() == expr);
Ethan Nicholascb670962017-04-20 19:31:52 -0400171 *iter = fNodes.erase(*iter);
172 return true;
173 }
174 case Expression::kTernary_Kind: {
175 // ternaries cross basic block boundaries, must regenerate the CFG to remove it
176 return false;
177 }
178 case Expression::kFieldAccess_Kind: {
179 FieldAccess* f = (FieldAccess*) expr;
180 if (!this->tryRemoveExpressionBefore(iter, f->fBase.get())) {
181 return false;
182 }
183 *iter = fNodes.erase(*iter);
184 return true;
185 }
186 case Expression::kSwizzle_Kind: {
187 Swizzle* s = (Swizzle*) expr;
188 if (!this->tryRemoveExpressionBefore(iter, s->fBase.get())) {
189 return false;
190 }
191 *iter = fNodes.erase(*iter);
192 return true;
193 }
194 case Expression::kIndex_Kind: {
195 IndexExpression* idx = (IndexExpression*) expr;
196 if (!this->tryRemoveExpressionBefore(iter, idx->fBase.get())) {
197 return false;
198 }
199 if (!this->tryRemoveExpressionBefore(iter, idx->fIndex.get())) {
200 return false;
201 }
202 *iter = fNodes.erase(*iter);
203 return true;
204 }
205 case Expression::kConstructor_Kind: {
206 Constructor* c = (Constructor*) expr;
207 for (auto& arg : c->fArguments) {
208 if (!this->tryRemoveExpressionBefore(iter, arg.get())) {
209 return false;
210 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400211 SkASSERT((*iter)->expression()->get() == expr);
Ethan Nicholascb670962017-04-20 19:31:52 -0400212 }
213 *iter = fNodes.erase(*iter);
214 return true;
215 }
216 case Expression::kFunctionCall_Kind: {
217 FunctionCall* f = (FunctionCall*) expr;
218 for (auto& arg : f->fArguments) {
219 if (!this->tryRemoveExpressionBefore(iter, arg.get())) {
220 return false;
221 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400222 SkASSERT((*iter)->expression()->get() == expr);
Ethan Nicholascb670962017-04-20 19:31:52 -0400223 }
224 *iter = fNodes.erase(*iter);
225 return true;
226 }
227 case Expression::kPrefix_Kind:
228 if (!this->tryRemoveExpressionBefore(iter,
229 ((PrefixExpression*) expr)->fOperand.get())) {
230 return false;
231 }
232 *iter = fNodes.erase(*iter);
233 return true;
234 case Expression::kPostfix_Kind:
235 if (!this->tryRemoveExpressionBefore(iter,
236 ((PrefixExpression*) expr)->fOperand.get())) {
237 return false;
238 }
239 *iter = fNodes.erase(*iter);
240 return true;
241 case Expression::kBoolLiteral_Kind: // fall through
242 case Expression::kFloatLiteral_Kind: // fall through
243 case Expression::kIntLiteral_Kind: // fall through
Ethan Nicholas762466e2017-06-29 10:03:38 -0400244 case Expression::kSetting_Kind: // fall through
Ethan Nicholascb670962017-04-20 19:31:52 -0400245 case Expression::kVariableReference_Kind:
246 *iter = fNodes.erase(*iter);
247 return true;
248 default:
249 ABORT("unhandled expression: %s\n", expr->description().c_str());
250 }
251}
252
253bool BasicBlock::tryInsertExpression(std::vector<BasicBlock::Node>::iterator* iter,
254 std::unique_ptr<Expression>* expr) {
255 switch ((*expr)->fKind) {
256 case Expression::kBinary_Kind: {
257 BinaryExpression* b = (BinaryExpression*) expr->get();
258 if (!this->tryInsertExpression(iter, &b->fRight)) {
259 return false;
260 }
261 ++(*iter);
262 if (!this->tryInsertExpression(iter, &b->fLeft)) {
263 return false;
264 }
265 ++(*iter);
266 BasicBlock::Node node = { BasicBlock::Node::kExpression_Kind, true, expr, nullptr };
267 *iter = fNodes.insert(*iter, node);
268 return true;
269 }
270 case Expression::kBoolLiteral_Kind: // fall through
271 case Expression::kFloatLiteral_Kind: // fall through
272 case Expression::kIntLiteral_Kind: // fall through
273 case Expression::kVariableReference_Kind: {
274 BasicBlock::Node node = { BasicBlock::Node::kExpression_Kind, true, expr, nullptr };
275 *iter = fNodes.insert(*iter, node);
276 return true;
277 }
278 case Expression::kConstructor_Kind: {
279 Constructor* c = (Constructor*) expr->get();
280 for (auto& arg : c->fArguments) {
281 if (!this->tryInsertExpression(iter, &arg)) {
282 return false;
283 }
284 ++(*iter);
285 }
286 BasicBlock::Node node = { BasicBlock::Node::kExpression_Kind, true, expr, nullptr };
287 *iter = fNodes.insert(*iter, node);
288 return true;
289 }
290 default:
291 return false;
292 }
293}
294
Ethan Nicholas86a43402017-01-19 13:32:00 -0500295void CFGGenerator::addExpression(CFG& cfg, std::unique_ptr<Expression>* e, bool constantPropagate) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400296 SkASSERT(e);
Ethan Nicholas86a43402017-01-19 13:32:00 -0500297 switch ((*e)->fKind) {
ethannicholas22f939e2016-10-13 13:25:34 -0700298 case Expression::kBinary_Kind: {
Ethan Nicholas86a43402017-01-19 13:32:00 -0500299 BinaryExpression* b = (BinaryExpression*) e->get();
ethannicholas22f939e2016-10-13 13:25:34 -0700300 switch (b->fOperator) {
301 case Token::LOGICALAND: // fall through
302 case Token::LOGICALOR: {
303 // this isn't as precise as it could be -- we don't bother to track that if we
304 // early exit from a logical and/or, we know which branch of an 'if' we're going
305 // to hit -- but it won't make much difference in practice.
Ethan Nicholas86a43402017-01-19 13:32:00 -0500306 this->addExpression(cfg, &b->fLeft, constantPropagate);
ethannicholas22f939e2016-10-13 13:25:34 -0700307 BlockId start = cfg.fCurrent;
308 cfg.newBlock();
Ethan Nicholas86a43402017-01-19 13:32:00 -0500309 this->addExpression(cfg, &b->fRight, constantPropagate);
ethannicholas22f939e2016-10-13 13:25:34 -0700310 cfg.newBlock();
311 cfg.addExit(start, cfg.fCurrent);
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400312 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({
313 BasicBlock::Node::kExpression_Kind,
314 constantPropagate,
315 e,
316 nullptr
317 });
ethannicholas22f939e2016-10-13 13:25:34 -0700318 break;
319 }
320 case Token::EQ: {
Ethan Nicholas86a43402017-01-19 13:32:00 -0500321 this->addExpression(cfg, &b->fRight, constantPropagate);
322 this->addLValue(cfg, &b->fLeft);
323 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({
324 BasicBlock::Node::kExpression_Kind,
325 constantPropagate,
326 e,
327 nullptr
ethannicholas22f939e2016-10-13 13:25:34 -0700328 });
329 break;
330 }
331 default:
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700332 this->addExpression(cfg, &b->fLeft, !Compiler::IsAssignment(b->fOperator));
Ethan Nicholas86a43402017-01-19 13:32:00 -0500333 this->addExpression(cfg, &b->fRight, constantPropagate);
334 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({
335 BasicBlock::Node::kExpression_Kind,
336 constantPropagate,
337 e,
338 nullptr
ethannicholas22f939e2016-10-13 13:25:34 -0700339 });
340 }
341 break;
342 }
343 case Expression::kConstructor_Kind: {
Ethan Nicholas86a43402017-01-19 13:32:00 -0500344 Constructor* c = (Constructor*) e->get();
345 for (auto& arg : c->fArguments) {
346 this->addExpression(cfg, &arg, constantPropagate);
ethannicholas22f939e2016-10-13 13:25:34 -0700347 }
Ethan Nicholas86a43402017-01-19 13:32:00 -0500348 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpression_Kind,
349 constantPropagate, e, nullptr });
ethannicholas22f939e2016-10-13 13:25:34 -0700350 break;
351 }
352 case Expression::kFunctionCall_Kind: {
Ethan Nicholas86a43402017-01-19 13:32:00 -0500353 FunctionCall* c = (FunctionCall*) e->get();
354 for (auto& arg : c->fArguments) {
355 this->addExpression(cfg, &arg, constantPropagate);
ethannicholas22f939e2016-10-13 13:25:34 -0700356 }
Ethan Nicholas86a43402017-01-19 13:32:00 -0500357 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpression_Kind,
358 constantPropagate, e, nullptr });
ethannicholas22f939e2016-10-13 13:25:34 -0700359 break;
360 }
361 case Expression::kFieldAccess_Kind:
Ethan Nicholas86a43402017-01-19 13:32:00 -0500362 this->addExpression(cfg, &((FieldAccess*) e->get())->fBase, constantPropagate);
363 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpression_Kind,
364 constantPropagate, e, nullptr });
ethannicholas22f939e2016-10-13 13:25:34 -0700365 break;
366 case Expression::kIndex_Kind:
Ethan Nicholas86a43402017-01-19 13:32:00 -0500367 this->addExpression(cfg, &((IndexExpression*) e->get())->fBase, constantPropagate);
368 this->addExpression(cfg, &((IndexExpression*) e->get())->fIndex, constantPropagate);
369 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpression_Kind,
370 constantPropagate, e, nullptr });
ethannicholas22f939e2016-10-13 13:25:34 -0700371 break;
Ethan Nicholasaf197692017-02-27 13:26:45 -0500372 case Expression::kPrefix_Kind: {
373 PrefixExpression* p = (PrefixExpression*) e->get();
374 this->addExpression(cfg, &p->fOperand, constantPropagate &&
375 p->fOperator != Token::PLUSPLUS &&
376 p->fOperator != Token::MINUSMINUS);
Ethan Nicholas86a43402017-01-19 13:32:00 -0500377 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpression_Kind,
378 constantPropagate, e, nullptr });
ethannicholas22f939e2016-10-13 13:25:34 -0700379 break;
Ethan Nicholasaf197692017-02-27 13:26:45 -0500380 }
ethannicholas22f939e2016-10-13 13:25:34 -0700381 case Expression::kPostfix_Kind:
Ethan Nicholasaf197692017-02-27 13:26:45 -0500382 this->addExpression(cfg, &((PostfixExpression*) e->get())->fOperand, false);
Ethan Nicholas86a43402017-01-19 13:32:00 -0500383 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpression_Kind,
384 constantPropagate, e, nullptr });
ethannicholas22f939e2016-10-13 13:25:34 -0700385 break;
386 case Expression::kSwizzle_Kind:
Ethan Nicholas86a43402017-01-19 13:32:00 -0500387 this->addExpression(cfg, &((Swizzle*) e->get())->fBase, constantPropagate);
388 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpression_Kind,
389 constantPropagate, e, nullptr });
ethannicholas22f939e2016-10-13 13:25:34 -0700390 break;
Ethan Nicholas91164d12019-05-15 15:29:54 -0400391 case Expression::kAppendStage_Kind: // fall through
392 case Expression::kBoolLiteral_Kind: // fall through
393 case Expression::kExternalValue_Kind: // fall through
394 case Expression::kFloatLiteral_Kind: // fall through
395 case Expression::kIntLiteral_Kind: // fall through
Ethan Nicholasee1c8a72019-02-22 10:50:47 -0500396 case Expression::kNullLiteral_Kind: // fall through
Ethan Nicholas91164d12019-05-15 15:29:54 -0400397 case Expression::kSetting_Kind: // fall through
ethannicholas22f939e2016-10-13 13:25:34 -0700398 case Expression::kVariableReference_Kind:
Ethan Nicholas86a43402017-01-19 13:32:00 -0500399 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpression_Kind,
400 constantPropagate, e, nullptr });
ethannicholas22f939e2016-10-13 13:25:34 -0700401 break;
402 case Expression::kTernary_Kind: {
Ethan Nicholas86a43402017-01-19 13:32:00 -0500403 TernaryExpression* t = (TernaryExpression*) e->get();
404 this->addExpression(cfg, &t->fTest, constantPropagate);
Ethan Nicholascb670962017-04-20 19:31:52 -0400405 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpression_Kind,
406 constantPropagate, e, nullptr });
ethannicholas22f939e2016-10-13 13:25:34 -0700407 BlockId start = cfg.fCurrent;
408 cfg.newBlock();
Ethan Nicholas86a43402017-01-19 13:32:00 -0500409 this->addExpression(cfg, &t->fIfTrue, constantPropagate);
ethannicholas22f939e2016-10-13 13:25:34 -0700410 BlockId next = cfg.newBlock();
411 cfg.fCurrent = start;
412 cfg.newBlock();
Ethan Nicholas86a43402017-01-19 13:32:00 -0500413 this->addExpression(cfg, &t->fIfFalse, constantPropagate);
ethannicholas22f939e2016-10-13 13:25:34 -0700414 cfg.addExit(cfg.fCurrent, next);
415 cfg.fCurrent = next;
416 break;
417 }
418 case Expression::kFunctionReference_Kind: // fall through
419 case Expression::kTypeReference_Kind: // fall through
420 case Expression::kDefined_Kind:
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400421 SkASSERT(false);
ethannicholas22f939e2016-10-13 13:25:34 -0700422 break;
423 }
424}
425
426// adds expressions that are evaluated as part of resolving an lvalue
Ethan Nicholas86a43402017-01-19 13:32:00 -0500427void CFGGenerator::addLValue(CFG& cfg, std::unique_ptr<Expression>* e) {
428 switch ((*e)->fKind) {
ethannicholas22f939e2016-10-13 13:25:34 -0700429 case Expression::kFieldAccess_Kind:
Ethan Nicholas86a43402017-01-19 13:32:00 -0500430 this->addLValue(cfg, &((FieldAccess&) **e).fBase);
ethannicholas22f939e2016-10-13 13:25:34 -0700431 break;
432 case Expression::kIndex_Kind:
Ethan Nicholas86a43402017-01-19 13:32:00 -0500433 this->addLValue(cfg, &((IndexExpression&) **e).fBase);
434 this->addExpression(cfg, &((IndexExpression&) **e).fIndex, true);
ethannicholas22f939e2016-10-13 13:25:34 -0700435 break;
436 case Expression::kSwizzle_Kind:
Ethan Nicholas86a43402017-01-19 13:32:00 -0500437 this->addLValue(cfg, &((Swizzle&) **e).fBase);
ethannicholas22f939e2016-10-13 13:25:34 -0700438 break;
Ethan Nicholas91164d12019-05-15 15:29:54 -0400439 case Expression::kExternalValue_Kind: // fall through
ethannicholas22f939e2016-10-13 13:25:34 -0700440 case Expression::kVariableReference_Kind:
441 break;
Ethan Nicholasa583b812018-01-18 13:32:11 -0500442 case Expression::kTernary_Kind:
443 this->addExpression(cfg, &((TernaryExpression&) **e).fTest, true);
444 // Technically we will of course only evaluate one or the other, but if the test turns
445 // out to be constant, the ternary will get collapsed down to just one branch anyway. So
446 // it should be ok to pretend that we always evaluate both branches here.
447 this->addLValue(cfg, &((TernaryExpression&) **e).fIfTrue);
448 this->addLValue(cfg, &((TernaryExpression&) **e).fIfFalse);
449 break;
ethannicholas22f939e2016-10-13 13:25:34 -0700450 default:
451 // not an lvalue, can't happen
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400452 SkASSERT(false);
ethannicholas22f939e2016-10-13 13:25:34 -0700453 break;
454 }
455}
456
Ethan Nicholas0d997662019-04-08 09:46:01 -0400457static bool is_true(Expression& expr) {
458 return expr.fKind == Expression::kBoolLiteral_Kind && ((BoolLiteral&) expr).fValue;
459}
460
Ethan Nicholascb670962017-04-20 19:31:52 -0400461void CFGGenerator::addStatement(CFG& cfg, std::unique_ptr<Statement>* s) {
462 switch ((*s)->fKind) {
ethannicholas22f939e2016-10-13 13:25:34 -0700463 case Statement::kBlock_Kind:
Ethan Nicholascb670962017-04-20 19:31:52 -0400464 for (auto& child : ((Block&) **s).fStatements) {
465 addStatement(cfg, &child);
ethannicholas22f939e2016-10-13 13:25:34 -0700466 }
467 break;
468 case Statement::kIf_Kind: {
Ethan Nicholascb670962017-04-20 19:31:52 -0400469 IfStatement& ifs = (IfStatement&) **s;
470 this->addExpression(cfg, &ifs.fTest, true);
471 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kStatement_Kind, false,
472 nullptr, s });
ethannicholas22f939e2016-10-13 13:25:34 -0700473 BlockId start = cfg.fCurrent;
474 cfg.newBlock();
Ethan Nicholascb670962017-04-20 19:31:52 -0400475 this->addStatement(cfg, &ifs.fIfTrue);
ethannicholas22f939e2016-10-13 13:25:34 -0700476 BlockId next = cfg.newBlock();
Ethan Nicholascb670962017-04-20 19:31:52 -0400477 if (ifs.fIfFalse) {
ethannicholas22f939e2016-10-13 13:25:34 -0700478 cfg.fCurrent = start;
479 cfg.newBlock();
Ethan Nicholascb670962017-04-20 19:31:52 -0400480 this->addStatement(cfg, &ifs.fIfFalse);
ethannicholas22f939e2016-10-13 13:25:34 -0700481 cfg.addExit(cfg.fCurrent, next);
482 cfg.fCurrent = next;
483 } else {
484 cfg.addExit(start, next);
485 }
486 break;
487 }
488 case Statement::kExpression_Kind: {
Ethan Nicholascb670962017-04-20 19:31:52 -0400489 this->addExpression(cfg, &((ExpressionStatement&) **s).fExpression, true);
490 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kStatement_Kind, false,
491 nullptr, s });
ethannicholas22f939e2016-10-13 13:25:34 -0700492 break;
493 }
494 case Statement::kVarDeclarations_Kind: {
Ethan Nicholas82a62d22017-11-07 14:42:10 +0000495 VarDeclarationsStatement& decls = ((VarDeclarationsStatement&) **s);
496 for (auto& stmt : decls.fDeclaration->fVars) {
497 if (stmt->fKind == Statement::kNop_Kind) {
498 continue;
499 }
500 VarDeclaration& vd = (VarDeclaration&) *stmt;
501 if (vd.fValue) {
502 this->addExpression(cfg, &vd.fValue, true);
503 }
504 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kStatement_Kind,
505 false, nullptr, &stmt });
506 }
Ethan Nicholas91a10532017-06-22 11:24:38 -0400507 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kStatement_Kind, false,
508 nullptr, s });
ethannicholas22f939e2016-10-13 13:25:34 -0700509 break;
510 }
511 case Statement::kDiscard_Kind:
Ethan Nicholas86a43402017-01-19 13:32:00 -0500512 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kStatement_Kind, false,
513 nullptr, s });
ethannicholas22f939e2016-10-13 13:25:34 -0700514 cfg.fCurrent = cfg.newIsolatedBlock();
515 break;
516 case Statement::kReturn_Kind: {
Ethan Nicholascb670962017-04-20 19:31:52 -0400517 ReturnStatement& r = ((ReturnStatement&) **s);
ethannicholas22f939e2016-10-13 13:25:34 -0700518 if (r.fExpression) {
Ethan Nicholas86a43402017-01-19 13:32:00 -0500519 this->addExpression(cfg, &r.fExpression, true);
ethannicholas22f939e2016-10-13 13:25:34 -0700520 }
Ethan Nicholas86a43402017-01-19 13:32:00 -0500521 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kStatement_Kind, false,
522 nullptr, s });
ethannicholas22f939e2016-10-13 13:25:34 -0700523 cfg.fCurrent = cfg.newIsolatedBlock();
524 break;
525 }
526 case Statement::kBreak_Kind:
Ethan Nicholas86a43402017-01-19 13:32:00 -0500527 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kStatement_Kind, false,
528 nullptr, s });
ethannicholas22f939e2016-10-13 13:25:34 -0700529 cfg.addExit(cfg.fCurrent, fLoopExits.top());
530 cfg.fCurrent = cfg.newIsolatedBlock();
531 break;
532 case Statement::kContinue_Kind:
Ethan Nicholas86a43402017-01-19 13:32:00 -0500533 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kStatement_Kind, false,
534 nullptr, s });
ethannicholas22f939e2016-10-13 13:25:34 -0700535 cfg.addExit(cfg.fCurrent, fLoopContinues.top());
536 cfg.fCurrent = cfg.newIsolatedBlock();
537 break;
538 case Statement::kWhile_Kind: {
Ethan Nicholascb670962017-04-20 19:31:52 -0400539 WhileStatement& w = (WhileStatement&) **s;
ethannicholas22f939e2016-10-13 13:25:34 -0700540 BlockId loopStart = cfg.newBlock();
541 fLoopContinues.push(loopStart);
542 BlockId loopExit = cfg.newIsolatedBlock();
543 fLoopExits.push(loopExit);
Ethan Nicholascb670962017-04-20 19:31:52 -0400544 this->addExpression(cfg, &w.fTest, true);
ethannicholas22f939e2016-10-13 13:25:34 -0700545 BlockId test = cfg.fCurrent;
Ethan Nicholas0d997662019-04-08 09:46:01 -0400546 if (!is_true(*w.fTest)) {
547 cfg.addExit(test, loopExit);
548 }
ethannicholas22f939e2016-10-13 13:25:34 -0700549 cfg.newBlock();
Ethan Nicholascb670962017-04-20 19:31:52 -0400550 this->addStatement(cfg, &w.fStatement);
ethannicholas22f939e2016-10-13 13:25:34 -0700551 cfg.addExit(cfg.fCurrent, loopStart);
552 fLoopContinues.pop();
553 fLoopExits.pop();
554 cfg.fCurrent = loopExit;
555 break;
556 }
557 case Statement::kDo_Kind: {
Ethan Nicholascb670962017-04-20 19:31:52 -0400558 DoStatement& d = (DoStatement&) **s;
ethannicholas22f939e2016-10-13 13:25:34 -0700559 BlockId loopStart = cfg.newBlock();
560 fLoopContinues.push(loopStart);
561 BlockId loopExit = cfg.newIsolatedBlock();
562 fLoopExits.push(loopExit);
Ethan Nicholascb670962017-04-20 19:31:52 -0400563 this->addStatement(cfg, &d.fStatement);
564 this->addExpression(cfg, &d.fTest, true);
ethannicholas22f939e2016-10-13 13:25:34 -0700565 cfg.addExit(cfg.fCurrent, loopExit);
566 cfg.addExit(cfg.fCurrent, loopStart);
567 fLoopContinues.pop();
568 fLoopExits.pop();
569 cfg.fCurrent = loopExit;
570 break;
571 }
572 case Statement::kFor_Kind: {
Ethan Nicholascb670962017-04-20 19:31:52 -0400573 ForStatement& f = (ForStatement&) **s;
574 if (f.fInitializer) {
575 this->addStatement(cfg, &f.fInitializer);
ethannicholas22f939e2016-10-13 13:25:34 -0700576 }
577 BlockId loopStart = cfg.newBlock();
578 BlockId next = cfg.newIsolatedBlock();
579 fLoopContinues.push(next);
580 BlockId loopExit = cfg.newIsolatedBlock();
581 fLoopExits.push(loopExit);
Ethan Nicholascb670962017-04-20 19:31:52 -0400582 if (f.fTest) {
583 this->addExpression(cfg, &f.fTest, true);
Ethan Nicholasd9fe7002017-05-30 10:15:34 -0400584 // this isn't quite right; we should have an exit from here to the loop exit, and
585 // remove the exit from the loop body to the loop exit. Structuring it like this
586 // forces the optimizer to believe that the loop body is always executed at least
587 // once. While not strictly correct, this avoids incorrect "variable not assigned"
588 // errors on variables which are assigned within the loop. The correct solution to
589 // this is to analyze the loop to see whether or not at least one iteration is
590 // guaranteed to happen, but for the time being we take the easy way out.
ethannicholas22f939e2016-10-13 13:25:34 -0700591 }
592 cfg.newBlock();
Ethan Nicholascb670962017-04-20 19:31:52 -0400593 this->addStatement(cfg, &f.fStatement);
ethannicholas22f939e2016-10-13 13:25:34 -0700594 cfg.addExit(cfg.fCurrent, next);
595 cfg.fCurrent = next;
Ethan Nicholascb670962017-04-20 19:31:52 -0400596 if (f.fNext) {
597 this->addExpression(cfg, &f.fNext, true);
ethannicholas22f939e2016-10-13 13:25:34 -0700598 }
Ethan Nicholas86a43402017-01-19 13:32:00 -0500599 cfg.addExit(cfg.fCurrent, loopStart);
Ethan Nicholasd9fe7002017-05-30 10:15:34 -0400600 cfg.addExit(cfg.fCurrent, loopExit);
ethannicholas22f939e2016-10-13 13:25:34 -0700601 fLoopContinues.pop();
602 fLoopExits.pop();
603 cfg.fCurrent = loopExit;
604 break;
605 }
Ethan Nicholasaf197692017-02-27 13:26:45 -0500606 case Statement::kSwitch_Kind: {
Ethan Nicholascb670962017-04-20 19:31:52 -0400607 SwitchStatement& ss = (SwitchStatement&) **s;
608 this->addExpression(cfg, &ss.fValue, true);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -0400609 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kStatement_Kind, false,
610 nullptr, s });
Ethan Nicholasaf197692017-02-27 13:26:45 -0500611 BlockId start = cfg.fCurrent;
612 BlockId switchExit = cfg.newIsolatedBlock();
613 fLoopExits.push(switchExit);
Ethan Nicholascb670962017-04-20 19:31:52 -0400614 for (const auto& c : ss.fCases) {
Ethan Nicholasaf197692017-02-27 13:26:45 -0500615 cfg.newBlock();
616 cfg.addExit(start, cfg.fCurrent);
Ethan Nicholaseace9352018-10-15 20:09:54 +0000617 if (c->fValue) {
618 // technically this should go in the start block, but it doesn't actually matter
619 // because it must be constant. Not worth running two loops for.
620 this->addExpression(cfg, &c->fValue, true);
621 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400622 for (auto& caseStatement : c->fStatements) {
623 this->addStatement(cfg, &caseStatement);
Ethan Nicholasaf197692017-02-27 13:26:45 -0500624 }
625 }
626 cfg.addExit(cfg.fCurrent, switchExit);
627 // note that unlike GLSL, our grammar requires the default case to be last
Ethan Nicholascb670962017-04-20 19:31:52 -0400628 if (0 == ss.fCases.size() || ss.fCases[ss.fCases.size() - 1]->fValue) {
Ethan Nicholasaf197692017-02-27 13:26:45 -0500629 // switch does not have a default clause, mark that it can skip straight to the end
630 cfg.addExit(start, switchExit);
631 }
632 fLoopExits.pop();
633 cfg.fCurrent = switchExit;
634 break;
635 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400636 case Statement::kNop_Kind:
637 break;
ethannicholas22f939e2016-10-13 13:25:34 -0700638 default:
Ethan Nicholascb670962017-04-20 19:31:52 -0400639 printf("statement: %s\n", (*s)->description().c_str());
ethannicholas22f939e2016-10-13 13:25:34 -0700640 ABORT("unsupported statement kind");
641 }
642}
643
Ethan Nicholascb670962017-04-20 19:31:52 -0400644CFG CFGGenerator::getCFG(FunctionDefinition& f) {
ethannicholas22f939e2016-10-13 13:25:34 -0700645 CFG result;
646 result.fStart = result.newBlock();
647 result.fCurrent = result.fStart;
Ethan Nicholascb670962017-04-20 19:31:52 -0400648 this->addStatement(result, &f.fBody);
ethannicholas22f939e2016-10-13 13:25:34 -0700649 result.newBlock();
650 result.fExit = result.fCurrent;
651 return result;
652}
653
654} // namespace