blob: be26279b8086f018ab577c89076bb86bf9c6c786 [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;
Ethan Nicholas409f6f02019-09-17 12:34:39 -0400189 if (s->fBase && !this->tryRemoveExpressionBefore(iter, s->fBase.get())) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400190 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 }
Ethan Nicholas409f6f02019-09-17 12:34:39 -0400291 case Expression::kSwizzle_Kind: {
292 Swizzle* s = (Swizzle*) expr->get();
293 if (!this->tryInsertExpression(iter, &s->fBase)) {
294 return false;
295 }
296 ++(*iter);
297 BasicBlock::Node node = { BasicBlock::Node::kExpression_Kind, true, expr, nullptr };
298 *iter = fNodes.insert(*iter, node);
299 return true;
300 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400301 default:
302 return false;
303 }
304}
305
Ethan Nicholas86a43402017-01-19 13:32:00 -0500306void CFGGenerator::addExpression(CFG& cfg, std::unique_ptr<Expression>* e, bool constantPropagate) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400307 SkASSERT(e);
Ethan Nicholas86a43402017-01-19 13:32:00 -0500308 switch ((*e)->fKind) {
ethannicholas22f939e2016-10-13 13:25:34 -0700309 case Expression::kBinary_Kind: {
Ethan Nicholas86a43402017-01-19 13:32:00 -0500310 BinaryExpression* b = (BinaryExpression*) e->get();
ethannicholas22f939e2016-10-13 13:25:34 -0700311 switch (b->fOperator) {
312 case Token::LOGICALAND: // fall through
313 case Token::LOGICALOR: {
314 // this isn't as precise as it could be -- we don't bother to track that if we
315 // early exit from a logical and/or, we know which branch of an 'if' we're going
316 // to hit -- but it won't make much difference in practice.
Ethan Nicholas86a43402017-01-19 13:32:00 -0500317 this->addExpression(cfg, &b->fLeft, constantPropagate);
ethannicholas22f939e2016-10-13 13:25:34 -0700318 BlockId start = cfg.fCurrent;
319 cfg.newBlock();
Ethan Nicholas86a43402017-01-19 13:32:00 -0500320 this->addExpression(cfg, &b->fRight, constantPropagate);
ethannicholas22f939e2016-10-13 13:25:34 -0700321 cfg.newBlock();
322 cfg.addExit(start, cfg.fCurrent);
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400323 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({
324 BasicBlock::Node::kExpression_Kind,
325 constantPropagate,
326 e,
327 nullptr
328 });
ethannicholas22f939e2016-10-13 13:25:34 -0700329 break;
330 }
331 case Token::EQ: {
Ethan Nicholas86a43402017-01-19 13:32:00 -0500332 this->addExpression(cfg, &b->fRight, constantPropagate);
333 this->addLValue(cfg, &b->fLeft);
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 break;
341 }
342 default:
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700343 this->addExpression(cfg, &b->fLeft, !Compiler::IsAssignment(b->fOperator));
Ethan Nicholas86a43402017-01-19 13:32:00 -0500344 this->addExpression(cfg, &b->fRight, constantPropagate);
345 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({
346 BasicBlock::Node::kExpression_Kind,
347 constantPropagate,
348 e,
349 nullptr
ethannicholas22f939e2016-10-13 13:25:34 -0700350 });
351 }
352 break;
353 }
354 case Expression::kConstructor_Kind: {
Ethan Nicholas86a43402017-01-19 13:32:00 -0500355 Constructor* c = (Constructor*) e->get();
356 for (auto& arg : c->fArguments) {
357 this->addExpression(cfg, &arg, constantPropagate);
ethannicholas22f939e2016-10-13 13:25:34 -0700358 }
Ethan Nicholas86a43402017-01-19 13:32:00 -0500359 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpression_Kind,
360 constantPropagate, e, nullptr });
ethannicholas22f939e2016-10-13 13:25:34 -0700361 break;
362 }
Ethan Nicholas9e6a3932019-05-17 16:31:21 -0400363 case Expression::kExternalFunctionCall_Kind: {
364 ExternalFunctionCall* c = (ExternalFunctionCall*) e->get();
365 for (auto& arg : c->fArguments) {
366 this->addExpression(cfg, &arg, constantPropagate);
367 }
368 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpression_Kind,
369 constantPropagate, e, nullptr });
370 break;
371 }
ethannicholas22f939e2016-10-13 13:25:34 -0700372 case Expression::kFunctionCall_Kind: {
Ethan Nicholas86a43402017-01-19 13:32:00 -0500373 FunctionCall* c = (FunctionCall*) e->get();
374 for (auto& arg : c->fArguments) {
375 this->addExpression(cfg, &arg, constantPropagate);
ethannicholas22f939e2016-10-13 13:25:34 -0700376 }
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;
380 }
381 case Expression::kFieldAccess_Kind:
Ethan Nicholas86a43402017-01-19 13:32:00 -0500382 this->addExpression(cfg, &((FieldAccess*) e->get())->fBase, constantPropagate);
383 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::kIndex_Kind:
Ethan Nicholas86a43402017-01-19 13:32:00 -0500387 this->addExpression(cfg, &((IndexExpression*) e->get())->fBase, constantPropagate);
388 this->addExpression(cfg, &((IndexExpression*) e->get())->fIndex, constantPropagate);
389 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpression_Kind,
390 constantPropagate, e, nullptr });
ethannicholas22f939e2016-10-13 13:25:34 -0700391 break;
Ethan Nicholasaf197692017-02-27 13:26:45 -0500392 case Expression::kPrefix_Kind: {
393 PrefixExpression* p = (PrefixExpression*) e->get();
394 this->addExpression(cfg, &p->fOperand, constantPropagate &&
395 p->fOperator != Token::PLUSPLUS &&
396 p->fOperator != Token::MINUSMINUS);
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;
Ethan Nicholasaf197692017-02-27 13:26:45 -0500400 }
ethannicholas22f939e2016-10-13 13:25:34 -0700401 case Expression::kPostfix_Kind:
Ethan Nicholasaf197692017-02-27 13:26:45 -0500402 this->addExpression(cfg, &((PostfixExpression*) e->get())->fOperand, false);
Ethan Nicholas86a43402017-01-19 13:32:00 -0500403 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpression_Kind,
404 constantPropagate, e, nullptr });
ethannicholas22f939e2016-10-13 13:25:34 -0700405 break;
406 case Expression::kSwizzle_Kind:
Ethan Nicholas86a43402017-01-19 13:32:00 -0500407 this->addExpression(cfg, &((Swizzle*) e->get())->fBase, constantPropagate);
408 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpression_Kind,
409 constantPropagate, e, nullptr });
ethannicholas22f939e2016-10-13 13:25:34 -0700410 break;
Ethan Nicholas91164d12019-05-15 15:29:54 -0400411 case Expression::kAppendStage_Kind: // fall through
412 case Expression::kBoolLiteral_Kind: // fall through
413 case Expression::kExternalValue_Kind: // fall through
414 case Expression::kFloatLiteral_Kind: // fall through
415 case Expression::kIntLiteral_Kind: // fall through
Ethan Nicholasee1c8a72019-02-22 10:50:47 -0500416 case Expression::kNullLiteral_Kind: // fall through
Ethan Nicholas91164d12019-05-15 15:29:54 -0400417 case Expression::kSetting_Kind: // fall through
ethannicholas22f939e2016-10-13 13:25:34 -0700418 case Expression::kVariableReference_Kind:
Ethan Nicholas86a43402017-01-19 13:32:00 -0500419 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpression_Kind,
420 constantPropagate, e, nullptr });
ethannicholas22f939e2016-10-13 13:25:34 -0700421 break;
422 case Expression::kTernary_Kind: {
Ethan Nicholas86a43402017-01-19 13:32:00 -0500423 TernaryExpression* t = (TernaryExpression*) e->get();
424 this->addExpression(cfg, &t->fTest, constantPropagate);
Ethan Nicholascb670962017-04-20 19:31:52 -0400425 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpression_Kind,
426 constantPropagate, e, nullptr });
ethannicholas22f939e2016-10-13 13:25:34 -0700427 BlockId start = cfg.fCurrent;
428 cfg.newBlock();
Ethan Nicholas86a43402017-01-19 13:32:00 -0500429 this->addExpression(cfg, &t->fIfTrue, constantPropagate);
ethannicholas22f939e2016-10-13 13:25:34 -0700430 BlockId next = cfg.newBlock();
431 cfg.fCurrent = start;
432 cfg.newBlock();
Ethan Nicholas86a43402017-01-19 13:32:00 -0500433 this->addExpression(cfg, &t->fIfFalse, constantPropagate);
ethannicholas22f939e2016-10-13 13:25:34 -0700434 cfg.addExit(cfg.fCurrent, next);
435 cfg.fCurrent = next;
436 break;
437 }
438 case Expression::kFunctionReference_Kind: // fall through
439 case Expression::kTypeReference_Kind: // fall through
440 case Expression::kDefined_Kind:
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400441 SkASSERT(false);
ethannicholas22f939e2016-10-13 13:25:34 -0700442 break;
443 }
444}
445
446// adds expressions that are evaluated as part of resolving an lvalue
Ethan Nicholas86a43402017-01-19 13:32:00 -0500447void CFGGenerator::addLValue(CFG& cfg, std::unique_ptr<Expression>* e) {
448 switch ((*e)->fKind) {
ethannicholas22f939e2016-10-13 13:25:34 -0700449 case Expression::kFieldAccess_Kind:
Ethan Nicholas86a43402017-01-19 13:32:00 -0500450 this->addLValue(cfg, &((FieldAccess&) **e).fBase);
ethannicholas22f939e2016-10-13 13:25:34 -0700451 break;
452 case Expression::kIndex_Kind:
Ethan Nicholas86a43402017-01-19 13:32:00 -0500453 this->addLValue(cfg, &((IndexExpression&) **e).fBase);
454 this->addExpression(cfg, &((IndexExpression&) **e).fIndex, true);
ethannicholas22f939e2016-10-13 13:25:34 -0700455 break;
456 case Expression::kSwizzle_Kind:
Ethan Nicholas86a43402017-01-19 13:32:00 -0500457 this->addLValue(cfg, &((Swizzle&) **e).fBase);
ethannicholas22f939e2016-10-13 13:25:34 -0700458 break;
Ethan Nicholas91164d12019-05-15 15:29:54 -0400459 case Expression::kExternalValue_Kind: // fall through
ethannicholas22f939e2016-10-13 13:25:34 -0700460 case Expression::kVariableReference_Kind:
461 break;
Ethan Nicholasa583b812018-01-18 13:32:11 -0500462 case Expression::kTernary_Kind:
463 this->addExpression(cfg, &((TernaryExpression&) **e).fTest, true);
464 // Technically we will of course only evaluate one or the other, but if the test turns
465 // out to be constant, the ternary will get collapsed down to just one branch anyway. So
466 // it should be ok to pretend that we always evaluate both branches here.
467 this->addLValue(cfg, &((TernaryExpression&) **e).fIfTrue);
468 this->addLValue(cfg, &((TernaryExpression&) **e).fIfFalse);
469 break;
ethannicholas22f939e2016-10-13 13:25:34 -0700470 default:
471 // not an lvalue, can't happen
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400472 SkASSERT(false);
ethannicholas22f939e2016-10-13 13:25:34 -0700473 break;
474 }
475}
476
Ethan Nicholas0d997662019-04-08 09:46:01 -0400477static bool is_true(Expression& expr) {
478 return expr.fKind == Expression::kBoolLiteral_Kind && ((BoolLiteral&) expr).fValue;
479}
480
Ethan Nicholascb670962017-04-20 19:31:52 -0400481void CFGGenerator::addStatement(CFG& cfg, std::unique_ptr<Statement>* s) {
482 switch ((*s)->fKind) {
ethannicholas22f939e2016-10-13 13:25:34 -0700483 case Statement::kBlock_Kind:
Ethan Nicholascb670962017-04-20 19:31:52 -0400484 for (auto& child : ((Block&) **s).fStatements) {
485 addStatement(cfg, &child);
ethannicholas22f939e2016-10-13 13:25:34 -0700486 }
487 break;
488 case Statement::kIf_Kind: {
Ethan Nicholascb670962017-04-20 19:31:52 -0400489 IfStatement& ifs = (IfStatement&) **s;
490 this->addExpression(cfg, &ifs.fTest, true);
491 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kStatement_Kind, false,
492 nullptr, s });
ethannicholas22f939e2016-10-13 13:25:34 -0700493 BlockId start = cfg.fCurrent;
494 cfg.newBlock();
Ethan Nicholascb670962017-04-20 19:31:52 -0400495 this->addStatement(cfg, &ifs.fIfTrue);
ethannicholas22f939e2016-10-13 13:25:34 -0700496 BlockId next = cfg.newBlock();
Ethan Nicholascb670962017-04-20 19:31:52 -0400497 if (ifs.fIfFalse) {
ethannicholas22f939e2016-10-13 13:25:34 -0700498 cfg.fCurrent = start;
499 cfg.newBlock();
Ethan Nicholascb670962017-04-20 19:31:52 -0400500 this->addStatement(cfg, &ifs.fIfFalse);
ethannicholas22f939e2016-10-13 13:25:34 -0700501 cfg.addExit(cfg.fCurrent, next);
502 cfg.fCurrent = next;
503 } else {
504 cfg.addExit(start, next);
505 }
506 break;
507 }
508 case Statement::kExpression_Kind: {
Ethan Nicholascb670962017-04-20 19:31:52 -0400509 this->addExpression(cfg, &((ExpressionStatement&) **s).fExpression, true);
510 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kStatement_Kind, false,
511 nullptr, s });
ethannicholas22f939e2016-10-13 13:25:34 -0700512 break;
513 }
514 case Statement::kVarDeclarations_Kind: {
Ethan Nicholas82a62d22017-11-07 14:42:10 +0000515 VarDeclarationsStatement& decls = ((VarDeclarationsStatement&) **s);
516 for (auto& stmt : decls.fDeclaration->fVars) {
517 if (stmt->fKind == Statement::kNop_Kind) {
518 continue;
519 }
520 VarDeclaration& vd = (VarDeclaration&) *stmt;
521 if (vd.fValue) {
522 this->addExpression(cfg, &vd.fValue, true);
523 }
524 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kStatement_Kind,
525 false, nullptr, &stmt });
526 }
Ethan Nicholas91a10532017-06-22 11:24:38 -0400527 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kStatement_Kind, false,
528 nullptr, s });
ethannicholas22f939e2016-10-13 13:25:34 -0700529 break;
530 }
531 case Statement::kDiscard_Kind:
Ethan Nicholas86a43402017-01-19 13:32:00 -0500532 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kStatement_Kind, false,
533 nullptr, s });
ethannicholas22f939e2016-10-13 13:25:34 -0700534 cfg.fCurrent = cfg.newIsolatedBlock();
535 break;
536 case Statement::kReturn_Kind: {
Ethan Nicholascb670962017-04-20 19:31:52 -0400537 ReturnStatement& r = ((ReturnStatement&) **s);
ethannicholas22f939e2016-10-13 13:25:34 -0700538 if (r.fExpression) {
Ethan Nicholas86a43402017-01-19 13:32:00 -0500539 this->addExpression(cfg, &r.fExpression, true);
ethannicholas22f939e2016-10-13 13:25:34 -0700540 }
Ethan Nicholas86a43402017-01-19 13:32:00 -0500541 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kStatement_Kind, false,
542 nullptr, s });
ethannicholas22f939e2016-10-13 13:25:34 -0700543 cfg.fCurrent = cfg.newIsolatedBlock();
544 break;
545 }
546 case Statement::kBreak_Kind:
Ethan Nicholas86a43402017-01-19 13:32:00 -0500547 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kStatement_Kind, false,
548 nullptr, s });
ethannicholas22f939e2016-10-13 13:25:34 -0700549 cfg.addExit(cfg.fCurrent, fLoopExits.top());
550 cfg.fCurrent = cfg.newIsolatedBlock();
551 break;
552 case Statement::kContinue_Kind:
Ethan Nicholas86a43402017-01-19 13:32:00 -0500553 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kStatement_Kind, false,
554 nullptr, s });
ethannicholas22f939e2016-10-13 13:25:34 -0700555 cfg.addExit(cfg.fCurrent, fLoopContinues.top());
556 cfg.fCurrent = cfg.newIsolatedBlock();
557 break;
558 case Statement::kWhile_Kind: {
Ethan Nicholascb670962017-04-20 19:31:52 -0400559 WhileStatement& w = (WhileStatement&) **s;
ethannicholas22f939e2016-10-13 13:25:34 -0700560 BlockId loopStart = cfg.newBlock();
561 fLoopContinues.push(loopStart);
562 BlockId loopExit = cfg.newIsolatedBlock();
563 fLoopExits.push(loopExit);
Ethan Nicholascb670962017-04-20 19:31:52 -0400564 this->addExpression(cfg, &w.fTest, true);
ethannicholas22f939e2016-10-13 13:25:34 -0700565 BlockId test = cfg.fCurrent;
Ethan Nicholas0d997662019-04-08 09:46:01 -0400566 if (!is_true(*w.fTest)) {
567 cfg.addExit(test, loopExit);
568 }
ethannicholas22f939e2016-10-13 13:25:34 -0700569 cfg.newBlock();
Ethan Nicholascb670962017-04-20 19:31:52 -0400570 this->addStatement(cfg, &w.fStatement);
ethannicholas22f939e2016-10-13 13:25:34 -0700571 cfg.addExit(cfg.fCurrent, loopStart);
572 fLoopContinues.pop();
573 fLoopExits.pop();
574 cfg.fCurrent = loopExit;
575 break;
576 }
577 case Statement::kDo_Kind: {
Ethan Nicholascb670962017-04-20 19:31:52 -0400578 DoStatement& d = (DoStatement&) **s;
ethannicholas22f939e2016-10-13 13:25:34 -0700579 BlockId loopStart = cfg.newBlock();
580 fLoopContinues.push(loopStart);
581 BlockId loopExit = cfg.newIsolatedBlock();
582 fLoopExits.push(loopExit);
Ethan Nicholascb670962017-04-20 19:31:52 -0400583 this->addStatement(cfg, &d.fStatement);
584 this->addExpression(cfg, &d.fTest, true);
ethannicholas22f939e2016-10-13 13:25:34 -0700585 cfg.addExit(cfg.fCurrent, loopExit);
586 cfg.addExit(cfg.fCurrent, loopStart);
587 fLoopContinues.pop();
588 fLoopExits.pop();
589 cfg.fCurrent = loopExit;
590 break;
591 }
592 case Statement::kFor_Kind: {
Ethan Nicholascb670962017-04-20 19:31:52 -0400593 ForStatement& f = (ForStatement&) **s;
594 if (f.fInitializer) {
595 this->addStatement(cfg, &f.fInitializer);
ethannicholas22f939e2016-10-13 13:25:34 -0700596 }
597 BlockId loopStart = cfg.newBlock();
598 BlockId next = cfg.newIsolatedBlock();
599 fLoopContinues.push(next);
600 BlockId loopExit = cfg.newIsolatedBlock();
601 fLoopExits.push(loopExit);
Ethan Nicholascb670962017-04-20 19:31:52 -0400602 if (f.fTest) {
603 this->addExpression(cfg, &f.fTest, true);
Ethan Nicholasd9fe7002017-05-30 10:15:34 -0400604 // this isn't quite right; we should have an exit from here to the loop exit, and
605 // remove the exit from the loop body to the loop exit. Structuring it like this
606 // forces the optimizer to believe that the loop body is always executed at least
607 // once. While not strictly correct, this avoids incorrect "variable not assigned"
608 // errors on variables which are assigned within the loop. The correct solution to
609 // this is to analyze the loop to see whether or not at least one iteration is
610 // guaranteed to happen, but for the time being we take the easy way out.
ethannicholas22f939e2016-10-13 13:25:34 -0700611 }
612 cfg.newBlock();
Ethan Nicholascb670962017-04-20 19:31:52 -0400613 this->addStatement(cfg, &f.fStatement);
ethannicholas22f939e2016-10-13 13:25:34 -0700614 cfg.addExit(cfg.fCurrent, next);
615 cfg.fCurrent = next;
Ethan Nicholascb670962017-04-20 19:31:52 -0400616 if (f.fNext) {
617 this->addExpression(cfg, &f.fNext, true);
ethannicholas22f939e2016-10-13 13:25:34 -0700618 }
Ethan Nicholas86a43402017-01-19 13:32:00 -0500619 cfg.addExit(cfg.fCurrent, loopStart);
Ethan Nicholasd9fe7002017-05-30 10:15:34 -0400620 cfg.addExit(cfg.fCurrent, loopExit);
ethannicholas22f939e2016-10-13 13:25:34 -0700621 fLoopContinues.pop();
622 fLoopExits.pop();
623 cfg.fCurrent = loopExit;
624 break;
625 }
Ethan Nicholasaf197692017-02-27 13:26:45 -0500626 case Statement::kSwitch_Kind: {
Ethan Nicholascb670962017-04-20 19:31:52 -0400627 SwitchStatement& ss = (SwitchStatement&) **s;
628 this->addExpression(cfg, &ss.fValue, true);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -0400629 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kStatement_Kind, false,
630 nullptr, s });
Ethan Nicholasaf197692017-02-27 13:26:45 -0500631 BlockId start = cfg.fCurrent;
632 BlockId switchExit = cfg.newIsolatedBlock();
633 fLoopExits.push(switchExit);
Ethan Nicholascb670962017-04-20 19:31:52 -0400634 for (const auto& c : ss.fCases) {
Ethan Nicholasaf197692017-02-27 13:26:45 -0500635 cfg.newBlock();
636 cfg.addExit(start, cfg.fCurrent);
Ethan Nicholaseace9352018-10-15 20:09:54 +0000637 if (c->fValue) {
638 // technically this should go in the start block, but it doesn't actually matter
639 // because it must be constant. Not worth running two loops for.
640 this->addExpression(cfg, &c->fValue, true);
641 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400642 for (auto& caseStatement : c->fStatements) {
643 this->addStatement(cfg, &caseStatement);
Ethan Nicholasaf197692017-02-27 13:26:45 -0500644 }
645 }
646 cfg.addExit(cfg.fCurrent, switchExit);
647 // note that unlike GLSL, our grammar requires the default case to be last
Ethan Nicholascb670962017-04-20 19:31:52 -0400648 if (0 == ss.fCases.size() || ss.fCases[ss.fCases.size() - 1]->fValue) {
Ethan Nicholasaf197692017-02-27 13:26:45 -0500649 // switch does not have a default clause, mark that it can skip straight to the end
650 cfg.addExit(start, switchExit);
651 }
652 fLoopExits.pop();
653 cfg.fCurrent = switchExit;
654 break;
655 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400656 case Statement::kNop_Kind:
657 break;
ethannicholas22f939e2016-10-13 13:25:34 -0700658 default:
Ethan Nicholascb670962017-04-20 19:31:52 -0400659 printf("statement: %s\n", (*s)->description().c_str());
ethannicholas22f939e2016-10-13 13:25:34 -0700660 ABORT("unsupported statement kind");
661 }
662}
663
Ethan Nicholascb670962017-04-20 19:31:52 -0400664CFG CFGGenerator::getCFG(FunctionDefinition& f) {
ethannicholas22f939e2016-10-13 13:25:34 -0700665 CFG result;
666 result.fStart = result.newBlock();
667 result.fCurrent = result.fStart;
Ethan Nicholascb670962017-04-20 19:31:52 -0400668 this->addStatement(result, &f.fBody);
ethannicholas22f939e2016-10-13 13:25:34 -0700669 result.newBlock();
670 result.fExit = result.fCurrent;
671 return result;
672}
673
674} // namespace