blob: 99700964ac5c22ea1bb8eb614b76b62ce509470d [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"
Ethan Nicholas9e6a3932019-05-17 16:31:21 -040014#include "src/sksl/ir/SkSLExternalFunctionCall.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050015#include "src/sksl/ir/SkSLFieldAccess.h"
16#include "src/sksl/ir/SkSLForStatement.h"
17#include "src/sksl/ir/SkSLFunctionCall.h"
18#include "src/sksl/ir/SkSLIfStatement.h"
19#include "src/sksl/ir/SkSLIndexExpression.h"
20#include "src/sksl/ir/SkSLPostfixExpression.h"
21#include "src/sksl/ir/SkSLPrefixExpression.h"
22#include "src/sksl/ir/SkSLReturnStatement.h"
23#include "src/sksl/ir/SkSLSwitchStatement.h"
24#include "src/sksl/ir/SkSLSwizzle.h"
25#include "src/sksl/ir/SkSLTernaryExpression.h"
26#include "src/sksl/ir/SkSLVarDeclarationsStatement.h"
27#include "src/sksl/ir/SkSLWhileStatement.h"
ethannicholas22f939e2016-10-13 13:25:34 -070028
29namespace SkSL {
30
31BlockId CFG::newBlock() {
32 BlockId result = fBlocks.size();
33 fBlocks.emplace_back();
34 if (fBlocks.size() > 1) {
35 this->addExit(fCurrent, result);
36 }
37 fCurrent = result;
38 return result;
39}
40
41BlockId CFG::newIsolatedBlock() {
42 BlockId result = fBlocks.size();
43 fBlocks.emplace_back();
44 return result;
45}
46
47void CFG::addExit(BlockId from, BlockId to) {
48 if (from == 0 || fBlocks[from].fEntrances.size()) {
49 fBlocks[from].fExits.insert(to);
50 fBlocks[to].fEntrances.insert(from);
51 }
52}
53
54void CFG::dump() {
55 for (size_t i = 0; i < fBlocks.size(); i++) {
56 printf("Block %d\n-------\nBefore: ", (int) i);
57 const char* separator = "";
58 for (auto iter = fBlocks[i].fBefore.begin(); iter != fBlocks[i].fBefore.end(); iter++) {
Ethan Nicholas86a43402017-01-19 13:32:00 -050059 printf("%s%s = %s", separator, iter->first->description().c_str(),
Ethan Nicholascb670962017-04-20 19:31:52 -040060 iter->second ? (*iter->second)->description().c_str() : "<undefined>");
ethannicholas22f939e2016-10-13 13:25:34 -070061 separator = ", ";
62 }
63 printf("\nEntrances: ");
64 separator = "";
65 for (BlockId b : fBlocks[i].fEntrances) {
66 printf("%s%d", separator, (int) b);
67 separator = ", ";
68 }
69 printf("\n");
70 for (size_t j = 0; j < fBlocks[i].fNodes.size(); j++) {
Ethan Nicholas86a43402017-01-19 13:32:00 -050071 BasicBlock::Node& n = fBlocks[i].fNodes[j];
Ethan Nicholascb670962017-04-20 19:31:52 -040072 printf("Node %d (%p): %s\n", (int) j, &n, n.fKind == BasicBlock::Node::kExpression_Kind
73 ? (*n.expression())->description().c_str()
74 : (*n.statement())->description().c_str());
ethannicholas22f939e2016-10-13 13:25:34 -070075 }
76 printf("Exits: ");
77 separator = "";
78 for (BlockId b : fBlocks[i].fExits) {
79 printf("%s%d", separator, (int) b);
80 separator = ", ";
81 }
82 printf("\n\n");
83 }
84}
85
Ethan Nicholascb670962017-04-20 19:31:52 -040086bool BasicBlock::tryRemoveExpressionBefore(std::vector<BasicBlock::Node>::iterator* iter,
87 Expression* e) {
88 if (e->fKind == Expression::kTernary_Kind) {
89 return false;
90 }
91 bool result;
92 if ((*iter)->fKind == BasicBlock::Node::kExpression_Kind) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -040093 SkASSERT((*iter)->expression()->get() != e);
Ethan Nicholascb670962017-04-20 19:31:52 -040094 Expression* old = (*iter)->expression()->get();
95 do {
96 if ((*iter) == fNodes.begin()) {
Ethan Nicholas4b330df2017-05-17 10:52:55 -040097 return false;
Ethan Nicholascb670962017-04-20 19:31:52 -040098 }
99 --(*iter);
100 } while ((*iter)->fKind != BasicBlock::Node::kExpression_Kind ||
101 (*iter)->expression()->get() != e);
102 result = this->tryRemoveExpression(iter);
103 while ((*iter)->fKind != BasicBlock::Node::kExpression_Kind ||
104 (*iter)->expression()->get() != old) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400105 SkASSERT(*iter != fNodes.end());
Ethan Nicholascb670962017-04-20 19:31:52 -0400106 ++(*iter);
107 }
108 } else {
109 Statement* old = (*iter)->statement()->get();
110 do {
111 if ((*iter) == fNodes.begin()) {
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400112 return false;
Ethan Nicholascb670962017-04-20 19:31:52 -0400113 }
114 --(*iter);
115 } while ((*iter)->fKind != BasicBlock::Node::kExpression_Kind ||
116 (*iter)->expression()->get() != e);
117 result = this->tryRemoveExpression(iter);
118 while ((*iter)->fKind != BasicBlock::Node::kStatement_Kind ||
119 (*iter)->statement()->get() != old) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400120 SkASSERT(*iter != fNodes.end());
Ethan Nicholascb670962017-04-20 19:31:52 -0400121 ++(*iter);
122 }
123 }
124 return result;
125}
126
127bool BasicBlock::tryRemoveLValueBefore(std::vector<BasicBlock::Node>::iterator* iter,
128 Expression* lvalue) {
129 switch (lvalue->fKind) {
Ethan Nicholas91164d12019-05-15 15:29:54 -0400130 case Expression::kExternalValue_Kind: // fall through
Ethan Nicholascb670962017-04-20 19:31:52 -0400131 case Expression::kVariableReference_Kind:
132 return true;
133 case Expression::kSwizzle_Kind:
134 return this->tryRemoveLValueBefore(iter, ((Swizzle*) lvalue)->fBase.get());
135 case Expression::kFieldAccess_Kind:
136 return this->tryRemoveLValueBefore(iter, ((FieldAccess*) lvalue)->fBase.get());
137 case Expression::kIndex_Kind:
138 if (!this->tryRemoveLValueBefore(iter, ((IndexExpression*) lvalue)->fBase.get())) {
139 return false;
140 }
141 return this->tryRemoveExpressionBefore(iter, ((IndexExpression*) lvalue)->fIndex.get());
Ethan Nicholasa583b812018-01-18 13:32:11 -0500142 case Expression::kTernary_Kind:
143 if (!this->tryRemoveExpressionBefore(iter,
144 ((TernaryExpression*) lvalue)->fTest.get())) {
145 return false;
146 }
147 if (!this->tryRemoveLValueBefore(iter, ((TernaryExpression*) lvalue)->fIfTrue.get())) {
148 return false;
149 }
150 return this->tryRemoveLValueBefore(iter, ((TernaryExpression*) lvalue)->fIfFalse.get());
Ethan Nicholascb670962017-04-20 19:31:52 -0400151 default:
152 ABORT("invalid lvalue: %s\n", lvalue->description().c_str());
153 }
154}
155
156bool BasicBlock::tryRemoveExpression(std::vector<BasicBlock::Node>::iterator* iter) {
157 Expression* expr = (*iter)->expression()->get();
158 switch (expr->fKind) {
159 case Expression::kBinary_Kind: {
160 BinaryExpression* b = (BinaryExpression*) expr;
161 if (b->fOperator == Token::EQ) {
162 if (!this->tryRemoveLValueBefore(iter, b->fLeft.get())) {
163 return false;
164 }
165 } else if (!this->tryRemoveExpressionBefore(iter, b->fLeft.get())) {
166 return false;
167 }
168 if (!this->tryRemoveExpressionBefore(iter, b->fRight.get())) {
169 return false;
170 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400171 SkASSERT((*iter)->expression()->get() == expr);
Ethan Nicholascb670962017-04-20 19:31:52 -0400172 *iter = fNodes.erase(*iter);
173 return true;
174 }
175 case Expression::kTernary_Kind: {
176 // ternaries cross basic block boundaries, must regenerate the CFG to remove it
177 return false;
178 }
179 case Expression::kFieldAccess_Kind: {
180 FieldAccess* f = (FieldAccess*) expr;
181 if (!this->tryRemoveExpressionBefore(iter, f->fBase.get())) {
182 return false;
183 }
184 *iter = fNodes.erase(*iter);
185 return true;
186 }
187 case Expression::kSwizzle_Kind: {
188 Swizzle* s = (Swizzle*) expr;
189 if (!this->tryRemoveExpressionBefore(iter, s->fBase.get())) {
190 return false;
191 }
192 *iter = fNodes.erase(*iter);
193 return true;
194 }
195 case Expression::kIndex_Kind: {
196 IndexExpression* idx = (IndexExpression*) expr;
197 if (!this->tryRemoveExpressionBefore(iter, idx->fBase.get())) {
198 return false;
199 }
200 if (!this->tryRemoveExpressionBefore(iter, idx->fIndex.get())) {
201 return false;
202 }
203 *iter = fNodes.erase(*iter);
204 return true;
205 }
206 case Expression::kConstructor_Kind: {
207 Constructor* c = (Constructor*) expr;
208 for (auto& arg : c->fArguments) {
209 if (!this->tryRemoveExpressionBefore(iter, arg.get())) {
210 return false;
211 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400212 SkASSERT((*iter)->expression()->get() == expr);
Ethan Nicholascb670962017-04-20 19:31:52 -0400213 }
214 *iter = fNodes.erase(*iter);
215 return true;
216 }
217 case Expression::kFunctionCall_Kind: {
218 FunctionCall* f = (FunctionCall*) expr;
219 for (auto& arg : f->fArguments) {
220 if (!this->tryRemoveExpressionBefore(iter, arg.get())) {
221 return false;
222 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400223 SkASSERT((*iter)->expression()->get() == expr);
Ethan Nicholascb670962017-04-20 19:31:52 -0400224 }
225 *iter = fNodes.erase(*iter);
226 return true;
227 }
228 case Expression::kPrefix_Kind:
229 if (!this->tryRemoveExpressionBefore(iter,
230 ((PrefixExpression*) expr)->fOperand.get())) {
231 return false;
232 }
233 *iter = fNodes.erase(*iter);
234 return true;
235 case Expression::kPostfix_Kind:
236 if (!this->tryRemoveExpressionBefore(iter,
237 ((PrefixExpression*) expr)->fOperand.get())) {
238 return false;
239 }
240 *iter = fNodes.erase(*iter);
241 return true;
242 case Expression::kBoolLiteral_Kind: // fall through
243 case Expression::kFloatLiteral_Kind: // fall through
244 case Expression::kIntLiteral_Kind: // fall through
Ethan Nicholas762466e2017-06-29 10:03:38 -0400245 case Expression::kSetting_Kind: // fall through
Ethan Nicholascb670962017-04-20 19:31:52 -0400246 case Expression::kVariableReference_Kind:
247 *iter = fNodes.erase(*iter);
248 return true;
249 default:
250 ABORT("unhandled expression: %s\n", expr->description().c_str());
251 }
252}
253
254bool BasicBlock::tryInsertExpression(std::vector<BasicBlock::Node>::iterator* iter,
255 std::unique_ptr<Expression>* expr) {
256 switch ((*expr)->fKind) {
257 case Expression::kBinary_Kind: {
258 BinaryExpression* b = (BinaryExpression*) expr->get();
259 if (!this->tryInsertExpression(iter, &b->fRight)) {
260 return false;
261 }
262 ++(*iter);
263 if (!this->tryInsertExpression(iter, &b->fLeft)) {
264 return false;
265 }
266 ++(*iter);
267 BasicBlock::Node node = { BasicBlock::Node::kExpression_Kind, true, expr, nullptr };
268 *iter = fNodes.insert(*iter, node);
269 return true;
270 }
271 case Expression::kBoolLiteral_Kind: // fall through
272 case Expression::kFloatLiteral_Kind: // fall through
273 case Expression::kIntLiteral_Kind: // fall through
274 case Expression::kVariableReference_Kind: {
275 BasicBlock::Node node = { BasicBlock::Node::kExpression_Kind, true, expr, nullptr };
276 *iter = fNodes.insert(*iter, node);
277 return true;
278 }
279 case Expression::kConstructor_Kind: {
280 Constructor* c = (Constructor*) expr->get();
281 for (auto& arg : c->fArguments) {
282 if (!this->tryInsertExpression(iter, &arg)) {
283 return false;
284 }
285 ++(*iter);
286 }
287 BasicBlock::Node node = { BasicBlock::Node::kExpression_Kind, true, expr, nullptr };
288 *iter = fNodes.insert(*iter, node);
289 return true;
290 }
291 default:
292 return false;
293 }
294}
295
Ethan Nicholas86a43402017-01-19 13:32:00 -0500296void CFGGenerator::addExpression(CFG& cfg, std::unique_ptr<Expression>* e, bool constantPropagate) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400297 SkASSERT(e);
Ethan Nicholas86a43402017-01-19 13:32:00 -0500298 switch ((*e)->fKind) {
ethannicholas22f939e2016-10-13 13:25:34 -0700299 case Expression::kBinary_Kind: {
Ethan Nicholas86a43402017-01-19 13:32:00 -0500300 BinaryExpression* b = (BinaryExpression*) e->get();
ethannicholas22f939e2016-10-13 13:25:34 -0700301 switch (b->fOperator) {
302 case Token::LOGICALAND: // fall through
303 case Token::LOGICALOR: {
304 // this isn't as precise as it could be -- we don't bother to track that if we
305 // early exit from a logical and/or, we know which branch of an 'if' we're going
306 // to hit -- but it won't make much difference in practice.
Ethan Nicholas86a43402017-01-19 13:32:00 -0500307 this->addExpression(cfg, &b->fLeft, constantPropagate);
ethannicholas22f939e2016-10-13 13:25:34 -0700308 BlockId start = cfg.fCurrent;
309 cfg.newBlock();
Ethan Nicholas86a43402017-01-19 13:32:00 -0500310 this->addExpression(cfg, &b->fRight, constantPropagate);
ethannicholas22f939e2016-10-13 13:25:34 -0700311 cfg.newBlock();
312 cfg.addExit(start, cfg.fCurrent);
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400313 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({
314 BasicBlock::Node::kExpression_Kind,
315 constantPropagate,
316 e,
317 nullptr
318 });
ethannicholas22f939e2016-10-13 13:25:34 -0700319 break;
320 }
321 case Token::EQ: {
Ethan Nicholas86a43402017-01-19 13:32:00 -0500322 this->addExpression(cfg, &b->fRight, constantPropagate);
323 this->addLValue(cfg, &b->fLeft);
324 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({
325 BasicBlock::Node::kExpression_Kind,
326 constantPropagate,
327 e,
328 nullptr
ethannicholas22f939e2016-10-13 13:25:34 -0700329 });
330 break;
331 }
332 default:
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700333 this->addExpression(cfg, &b->fLeft, !Compiler::IsAssignment(b->fOperator));
Ethan Nicholas86a43402017-01-19 13:32:00 -0500334 this->addExpression(cfg, &b->fRight, constantPropagate);
335 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({
336 BasicBlock::Node::kExpression_Kind,
337 constantPropagate,
338 e,
339 nullptr
ethannicholas22f939e2016-10-13 13:25:34 -0700340 });
341 }
342 break;
343 }
344 case Expression::kConstructor_Kind: {
Ethan Nicholas86a43402017-01-19 13:32:00 -0500345 Constructor* c = (Constructor*) e->get();
346 for (auto& arg : c->fArguments) {
347 this->addExpression(cfg, &arg, constantPropagate);
ethannicholas22f939e2016-10-13 13:25:34 -0700348 }
Ethan Nicholas86a43402017-01-19 13:32:00 -0500349 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpression_Kind,
350 constantPropagate, e, nullptr });
ethannicholas22f939e2016-10-13 13:25:34 -0700351 break;
352 }
Ethan Nicholas9e6a3932019-05-17 16:31:21 -0400353 case Expression::kExternalFunctionCall_Kind: {
354 ExternalFunctionCall* c = (ExternalFunctionCall*) e->get();
355 for (auto& arg : c->fArguments) {
356 this->addExpression(cfg, &arg, constantPropagate);
357 }
358 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpression_Kind,
359 constantPropagate, e, nullptr });
360 break;
361 }
ethannicholas22f939e2016-10-13 13:25:34 -0700362 case Expression::kFunctionCall_Kind: {
Ethan Nicholas86a43402017-01-19 13:32:00 -0500363 FunctionCall* c = (FunctionCall*) e->get();
364 for (auto& arg : c->fArguments) {
365 this->addExpression(cfg, &arg, constantPropagate);
ethannicholas22f939e2016-10-13 13:25:34 -0700366 }
Ethan Nicholas86a43402017-01-19 13:32:00 -0500367 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpression_Kind,
368 constantPropagate, e, nullptr });
ethannicholas22f939e2016-10-13 13:25:34 -0700369 break;
370 }
371 case Expression::kFieldAccess_Kind:
Ethan Nicholas86a43402017-01-19 13:32:00 -0500372 this->addExpression(cfg, &((FieldAccess*) e->get())->fBase, constantPropagate);
373 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpression_Kind,
374 constantPropagate, e, nullptr });
ethannicholas22f939e2016-10-13 13:25:34 -0700375 break;
376 case Expression::kIndex_Kind:
Ethan Nicholas86a43402017-01-19 13:32:00 -0500377 this->addExpression(cfg, &((IndexExpression*) e->get())->fBase, constantPropagate);
378 this->addExpression(cfg, &((IndexExpression*) e->get())->fIndex, constantPropagate);
379 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpression_Kind,
380 constantPropagate, e, nullptr });
ethannicholas22f939e2016-10-13 13:25:34 -0700381 break;
Ethan Nicholasaf197692017-02-27 13:26:45 -0500382 case Expression::kPrefix_Kind: {
383 PrefixExpression* p = (PrefixExpression*) e->get();
384 this->addExpression(cfg, &p->fOperand, constantPropagate &&
385 p->fOperator != Token::PLUSPLUS &&
386 p->fOperator != Token::MINUSMINUS);
Ethan Nicholas86a43402017-01-19 13:32:00 -0500387 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpression_Kind,
388 constantPropagate, e, nullptr });
ethannicholas22f939e2016-10-13 13:25:34 -0700389 break;
Ethan Nicholasaf197692017-02-27 13:26:45 -0500390 }
ethannicholas22f939e2016-10-13 13:25:34 -0700391 case Expression::kPostfix_Kind:
Ethan Nicholasaf197692017-02-27 13:26:45 -0500392 this->addExpression(cfg, &((PostfixExpression*) e->get())->fOperand, false);
Ethan Nicholas86a43402017-01-19 13:32:00 -0500393 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpression_Kind,
394 constantPropagate, e, nullptr });
ethannicholas22f939e2016-10-13 13:25:34 -0700395 break;
396 case Expression::kSwizzle_Kind:
Ethan Nicholas86a43402017-01-19 13:32:00 -0500397 this->addExpression(cfg, &((Swizzle*) e->get())->fBase, constantPropagate);
398 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpression_Kind,
399 constantPropagate, e, nullptr });
ethannicholas22f939e2016-10-13 13:25:34 -0700400 break;
Ethan Nicholas91164d12019-05-15 15:29:54 -0400401 case Expression::kAppendStage_Kind: // fall through
402 case Expression::kBoolLiteral_Kind: // fall through
403 case Expression::kExternalValue_Kind: // fall through
404 case Expression::kFloatLiteral_Kind: // fall through
405 case Expression::kIntLiteral_Kind: // fall through
Ethan Nicholasee1c8a72019-02-22 10:50:47 -0500406 case Expression::kNullLiteral_Kind: // fall through
Ethan Nicholas91164d12019-05-15 15:29:54 -0400407 case Expression::kSetting_Kind: // fall through
ethannicholas22f939e2016-10-13 13:25:34 -0700408 case Expression::kVariableReference_Kind:
Ethan Nicholas86a43402017-01-19 13:32:00 -0500409 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpression_Kind,
410 constantPropagate, e, nullptr });
ethannicholas22f939e2016-10-13 13:25:34 -0700411 break;
412 case Expression::kTernary_Kind: {
Ethan Nicholas86a43402017-01-19 13:32:00 -0500413 TernaryExpression* t = (TernaryExpression*) e->get();
414 this->addExpression(cfg, &t->fTest, constantPropagate);
Ethan Nicholascb670962017-04-20 19:31:52 -0400415 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpression_Kind,
416 constantPropagate, e, nullptr });
ethannicholas22f939e2016-10-13 13:25:34 -0700417 BlockId start = cfg.fCurrent;
418 cfg.newBlock();
Ethan Nicholas86a43402017-01-19 13:32:00 -0500419 this->addExpression(cfg, &t->fIfTrue, constantPropagate);
ethannicholas22f939e2016-10-13 13:25:34 -0700420 BlockId next = cfg.newBlock();
421 cfg.fCurrent = start;
422 cfg.newBlock();
Ethan Nicholas86a43402017-01-19 13:32:00 -0500423 this->addExpression(cfg, &t->fIfFalse, constantPropagate);
ethannicholas22f939e2016-10-13 13:25:34 -0700424 cfg.addExit(cfg.fCurrent, next);
425 cfg.fCurrent = next;
426 break;
427 }
428 case Expression::kFunctionReference_Kind: // fall through
429 case Expression::kTypeReference_Kind: // fall through
430 case Expression::kDefined_Kind:
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400431 SkASSERT(false);
ethannicholas22f939e2016-10-13 13:25:34 -0700432 break;
433 }
434}
435
436// adds expressions that are evaluated as part of resolving an lvalue
Ethan Nicholas86a43402017-01-19 13:32:00 -0500437void CFGGenerator::addLValue(CFG& cfg, std::unique_ptr<Expression>* e) {
438 switch ((*e)->fKind) {
ethannicholas22f939e2016-10-13 13:25:34 -0700439 case Expression::kFieldAccess_Kind:
Ethan Nicholas86a43402017-01-19 13:32:00 -0500440 this->addLValue(cfg, &((FieldAccess&) **e).fBase);
ethannicholas22f939e2016-10-13 13:25:34 -0700441 break;
442 case Expression::kIndex_Kind:
Ethan Nicholas86a43402017-01-19 13:32:00 -0500443 this->addLValue(cfg, &((IndexExpression&) **e).fBase);
444 this->addExpression(cfg, &((IndexExpression&) **e).fIndex, true);
ethannicholas22f939e2016-10-13 13:25:34 -0700445 break;
446 case Expression::kSwizzle_Kind:
Ethan Nicholas86a43402017-01-19 13:32:00 -0500447 this->addLValue(cfg, &((Swizzle&) **e).fBase);
ethannicholas22f939e2016-10-13 13:25:34 -0700448 break;
Ethan Nicholas91164d12019-05-15 15:29:54 -0400449 case Expression::kExternalValue_Kind: // fall through
ethannicholas22f939e2016-10-13 13:25:34 -0700450 case Expression::kVariableReference_Kind:
451 break;
Ethan Nicholasa583b812018-01-18 13:32:11 -0500452 case Expression::kTernary_Kind:
453 this->addExpression(cfg, &((TernaryExpression&) **e).fTest, true);
454 // Technically we will of course only evaluate one or the other, but if the test turns
455 // out to be constant, the ternary will get collapsed down to just one branch anyway. So
456 // it should be ok to pretend that we always evaluate both branches here.
457 this->addLValue(cfg, &((TernaryExpression&) **e).fIfTrue);
458 this->addLValue(cfg, &((TernaryExpression&) **e).fIfFalse);
459 break;
ethannicholas22f939e2016-10-13 13:25:34 -0700460 default:
461 // not an lvalue, can't happen
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400462 SkASSERT(false);
ethannicholas22f939e2016-10-13 13:25:34 -0700463 break;
464 }
465}
466
Ethan Nicholas0d997662019-04-08 09:46:01 -0400467static bool is_true(Expression& expr) {
468 return expr.fKind == Expression::kBoolLiteral_Kind && ((BoolLiteral&) expr).fValue;
469}
470
Ethan Nicholascb670962017-04-20 19:31:52 -0400471void CFGGenerator::addStatement(CFG& cfg, std::unique_ptr<Statement>* s) {
472 switch ((*s)->fKind) {
ethannicholas22f939e2016-10-13 13:25:34 -0700473 case Statement::kBlock_Kind:
Ethan Nicholascb670962017-04-20 19:31:52 -0400474 for (auto& child : ((Block&) **s).fStatements) {
475 addStatement(cfg, &child);
ethannicholas22f939e2016-10-13 13:25:34 -0700476 }
477 break;
478 case Statement::kIf_Kind: {
Ethan Nicholascb670962017-04-20 19:31:52 -0400479 IfStatement& ifs = (IfStatement&) **s;
480 this->addExpression(cfg, &ifs.fTest, true);
481 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kStatement_Kind, false,
482 nullptr, s });
ethannicholas22f939e2016-10-13 13:25:34 -0700483 BlockId start = cfg.fCurrent;
484 cfg.newBlock();
Ethan Nicholascb670962017-04-20 19:31:52 -0400485 this->addStatement(cfg, &ifs.fIfTrue);
ethannicholas22f939e2016-10-13 13:25:34 -0700486 BlockId next = cfg.newBlock();
Ethan Nicholascb670962017-04-20 19:31:52 -0400487 if (ifs.fIfFalse) {
ethannicholas22f939e2016-10-13 13:25:34 -0700488 cfg.fCurrent = start;
489 cfg.newBlock();
Ethan Nicholascb670962017-04-20 19:31:52 -0400490 this->addStatement(cfg, &ifs.fIfFalse);
ethannicholas22f939e2016-10-13 13:25:34 -0700491 cfg.addExit(cfg.fCurrent, next);
492 cfg.fCurrent = next;
493 } else {
494 cfg.addExit(start, next);
495 }
496 break;
497 }
498 case Statement::kExpression_Kind: {
Ethan Nicholascb670962017-04-20 19:31:52 -0400499 this->addExpression(cfg, &((ExpressionStatement&) **s).fExpression, true);
500 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kStatement_Kind, false,
501 nullptr, s });
ethannicholas22f939e2016-10-13 13:25:34 -0700502 break;
503 }
504 case Statement::kVarDeclarations_Kind: {
Ethan Nicholas82a62d22017-11-07 14:42:10 +0000505 VarDeclarationsStatement& decls = ((VarDeclarationsStatement&) **s);
506 for (auto& stmt : decls.fDeclaration->fVars) {
507 if (stmt->fKind == Statement::kNop_Kind) {
508 continue;
509 }
510 VarDeclaration& vd = (VarDeclaration&) *stmt;
511 if (vd.fValue) {
512 this->addExpression(cfg, &vd.fValue, true);
513 }
514 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kStatement_Kind,
515 false, nullptr, &stmt });
516 }
Ethan Nicholas91a10532017-06-22 11:24:38 -0400517 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kStatement_Kind, false,
518 nullptr, s });
ethannicholas22f939e2016-10-13 13:25:34 -0700519 break;
520 }
521 case Statement::kDiscard_Kind:
Ethan Nicholas86a43402017-01-19 13:32:00 -0500522 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kStatement_Kind, false,
523 nullptr, s });
ethannicholas22f939e2016-10-13 13:25:34 -0700524 cfg.fCurrent = cfg.newIsolatedBlock();
525 break;
526 case Statement::kReturn_Kind: {
Ethan Nicholascb670962017-04-20 19:31:52 -0400527 ReturnStatement& r = ((ReturnStatement&) **s);
ethannicholas22f939e2016-10-13 13:25:34 -0700528 if (r.fExpression) {
Ethan Nicholas86a43402017-01-19 13:32:00 -0500529 this->addExpression(cfg, &r.fExpression, true);
ethannicholas22f939e2016-10-13 13:25:34 -0700530 }
Ethan Nicholas86a43402017-01-19 13:32:00 -0500531 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kStatement_Kind, false,
532 nullptr, s });
ethannicholas22f939e2016-10-13 13:25:34 -0700533 cfg.fCurrent = cfg.newIsolatedBlock();
534 break;
535 }
536 case Statement::kBreak_Kind:
Ethan Nicholas86a43402017-01-19 13:32:00 -0500537 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kStatement_Kind, false,
538 nullptr, s });
ethannicholas22f939e2016-10-13 13:25:34 -0700539 cfg.addExit(cfg.fCurrent, fLoopExits.top());
540 cfg.fCurrent = cfg.newIsolatedBlock();
541 break;
542 case Statement::kContinue_Kind:
Ethan Nicholas86a43402017-01-19 13:32:00 -0500543 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kStatement_Kind, false,
544 nullptr, s });
ethannicholas22f939e2016-10-13 13:25:34 -0700545 cfg.addExit(cfg.fCurrent, fLoopContinues.top());
546 cfg.fCurrent = cfg.newIsolatedBlock();
547 break;
548 case Statement::kWhile_Kind: {
Ethan Nicholascb670962017-04-20 19:31:52 -0400549 WhileStatement& w = (WhileStatement&) **s;
ethannicholas22f939e2016-10-13 13:25:34 -0700550 BlockId loopStart = cfg.newBlock();
551 fLoopContinues.push(loopStart);
552 BlockId loopExit = cfg.newIsolatedBlock();
553 fLoopExits.push(loopExit);
Ethan Nicholascb670962017-04-20 19:31:52 -0400554 this->addExpression(cfg, &w.fTest, true);
ethannicholas22f939e2016-10-13 13:25:34 -0700555 BlockId test = cfg.fCurrent;
Ethan Nicholas0d997662019-04-08 09:46:01 -0400556 if (!is_true(*w.fTest)) {
557 cfg.addExit(test, loopExit);
558 }
ethannicholas22f939e2016-10-13 13:25:34 -0700559 cfg.newBlock();
Ethan Nicholascb670962017-04-20 19:31:52 -0400560 this->addStatement(cfg, &w.fStatement);
ethannicholas22f939e2016-10-13 13:25:34 -0700561 cfg.addExit(cfg.fCurrent, loopStart);
562 fLoopContinues.pop();
563 fLoopExits.pop();
564 cfg.fCurrent = loopExit;
565 break;
566 }
567 case Statement::kDo_Kind: {
Ethan Nicholascb670962017-04-20 19:31:52 -0400568 DoStatement& d = (DoStatement&) **s;
ethannicholas22f939e2016-10-13 13:25:34 -0700569 BlockId loopStart = cfg.newBlock();
570 fLoopContinues.push(loopStart);
571 BlockId loopExit = cfg.newIsolatedBlock();
572 fLoopExits.push(loopExit);
Ethan Nicholascb670962017-04-20 19:31:52 -0400573 this->addStatement(cfg, &d.fStatement);
574 this->addExpression(cfg, &d.fTest, true);
ethannicholas22f939e2016-10-13 13:25:34 -0700575 cfg.addExit(cfg.fCurrent, loopExit);
576 cfg.addExit(cfg.fCurrent, loopStart);
577 fLoopContinues.pop();
578 fLoopExits.pop();
579 cfg.fCurrent = loopExit;
580 break;
581 }
582 case Statement::kFor_Kind: {
Ethan Nicholascb670962017-04-20 19:31:52 -0400583 ForStatement& f = (ForStatement&) **s;
584 if (f.fInitializer) {
585 this->addStatement(cfg, &f.fInitializer);
ethannicholas22f939e2016-10-13 13:25:34 -0700586 }
587 BlockId loopStart = cfg.newBlock();
588 BlockId next = cfg.newIsolatedBlock();
589 fLoopContinues.push(next);
590 BlockId loopExit = cfg.newIsolatedBlock();
591 fLoopExits.push(loopExit);
Ethan Nicholascb670962017-04-20 19:31:52 -0400592 if (f.fTest) {
593 this->addExpression(cfg, &f.fTest, true);
Ethan Nicholasd9fe7002017-05-30 10:15:34 -0400594 // this isn't quite right; we should have an exit from here to the loop exit, and
595 // remove the exit from the loop body to the loop exit. Structuring it like this
596 // forces the optimizer to believe that the loop body is always executed at least
597 // once. While not strictly correct, this avoids incorrect "variable not assigned"
598 // errors on variables which are assigned within the loop. The correct solution to
599 // this is to analyze the loop to see whether or not at least one iteration is
600 // guaranteed to happen, but for the time being we take the easy way out.
ethannicholas22f939e2016-10-13 13:25:34 -0700601 }
602 cfg.newBlock();
Ethan Nicholascb670962017-04-20 19:31:52 -0400603 this->addStatement(cfg, &f.fStatement);
ethannicholas22f939e2016-10-13 13:25:34 -0700604 cfg.addExit(cfg.fCurrent, next);
605 cfg.fCurrent = next;
Ethan Nicholascb670962017-04-20 19:31:52 -0400606 if (f.fNext) {
607 this->addExpression(cfg, &f.fNext, true);
ethannicholas22f939e2016-10-13 13:25:34 -0700608 }
Ethan Nicholas86a43402017-01-19 13:32:00 -0500609 cfg.addExit(cfg.fCurrent, loopStart);
Ethan Nicholasd9fe7002017-05-30 10:15:34 -0400610 cfg.addExit(cfg.fCurrent, loopExit);
ethannicholas22f939e2016-10-13 13:25:34 -0700611 fLoopContinues.pop();
612 fLoopExits.pop();
613 cfg.fCurrent = loopExit;
614 break;
615 }
Ethan Nicholasaf197692017-02-27 13:26:45 -0500616 case Statement::kSwitch_Kind: {
Ethan Nicholascb670962017-04-20 19:31:52 -0400617 SwitchStatement& ss = (SwitchStatement&) **s;
618 this->addExpression(cfg, &ss.fValue, true);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -0400619 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kStatement_Kind, false,
620 nullptr, s });
Ethan Nicholasaf197692017-02-27 13:26:45 -0500621 BlockId start = cfg.fCurrent;
622 BlockId switchExit = cfg.newIsolatedBlock();
623 fLoopExits.push(switchExit);
Ethan Nicholascb670962017-04-20 19:31:52 -0400624 for (const auto& c : ss.fCases) {
Ethan Nicholasaf197692017-02-27 13:26:45 -0500625 cfg.newBlock();
626 cfg.addExit(start, cfg.fCurrent);
Ethan Nicholaseace9352018-10-15 20:09:54 +0000627 if (c->fValue) {
628 // technically this should go in the start block, but it doesn't actually matter
629 // because it must be constant. Not worth running two loops for.
630 this->addExpression(cfg, &c->fValue, true);
631 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400632 for (auto& caseStatement : c->fStatements) {
633 this->addStatement(cfg, &caseStatement);
Ethan Nicholasaf197692017-02-27 13:26:45 -0500634 }
635 }
636 cfg.addExit(cfg.fCurrent, switchExit);
637 // note that unlike GLSL, our grammar requires the default case to be last
Ethan Nicholascb670962017-04-20 19:31:52 -0400638 if (0 == ss.fCases.size() || ss.fCases[ss.fCases.size() - 1]->fValue) {
Ethan Nicholasaf197692017-02-27 13:26:45 -0500639 // switch does not have a default clause, mark that it can skip straight to the end
640 cfg.addExit(start, switchExit);
641 }
642 fLoopExits.pop();
643 cfg.fCurrent = switchExit;
644 break;
645 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400646 case Statement::kNop_Kind:
647 break;
ethannicholas22f939e2016-10-13 13:25:34 -0700648 default:
Ethan Nicholascb670962017-04-20 19:31:52 -0400649 printf("statement: %s\n", (*s)->description().c_str());
ethannicholas22f939e2016-10-13 13:25:34 -0700650 ABORT("unsupported statement kind");
651 }
652}
653
Ethan Nicholascb670962017-04-20 19:31:52 -0400654CFG CFGGenerator::getCFG(FunctionDefinition& f) {
ethannicholas22f939e2016-10-13 13:25:34 -0700655 CFG result;
656 result.fStart = result.newBlock();
657 result.fCurrent = result.fStart;
Ethan Nicholascb670962017-04-20 19:31:52 -0400658 this->addStatement(result, &f.fBody);
ethannicholas22f939e2016-10-13 13:25:34 -0700659 result.newBlock();
660 result.fExit = result.fCurrent;
661 return result;
662}
663
664} // namespace