Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(290)

Side by Side Diff: src/sksl/SkSLCFGGenerator.cpp

Issue 2405383003: added basic dataflow analysis to skslc (Closed)
Patch Set: various fixes Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 /*
2 * Copyright 2016 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #include "SkSLCFGGenerator.h"
9
10 #include "ir/SkSLConstructor.h"
11 #include "ir/SkSLBinaryExpression.h"
12 #include "ir/SkSLDoStatement.h"
13 #include "ir/SkSLExpressionStatement.h"
14 #include "ir/SkSLFieldAccess.h"
15 #include "ir/SkSLForStatement.h"
16 #include "ir/SkSLFunctionCall.h"
17 #include "ir/SkSLIfStatement.h"
18 #include "ir/SkSLIndexExpression.h"
19 #include "ir/SkSLPostfixExpression.h"
20 #include "ir/SkSLPrefixExpression.h"
21 #include "ir/SkSLSwizzle.h"
22 #include "ir/SkSLTernaryExpression.h"
23 #include "ir/SkSLWhileStatement.h"
24
25 namespace SkSL {
26
27 BlockId CFG::newBlock() {
28 BlockId result = fBlocks.size();
29 fBlocks.emplace_back();
30 if (fBlocks.size() > 1) {
31 this->addExit(fCurrent, result);
32 }
33 fCurrent = result;
34 return result;
35 }
36
37 BlockId CFG::newIsolatedBlock() {
38 BlockId result = fBlocks.size();
39 fBlocks.emplace_back();
40 return result;
41 }
42
43 void CFG::addExit(BlockId from, BlockId to) {
44 if (from == 0 || fBlocks[from].fEntrances.size()) {
dogben 2016/10/13 03:55:43 I don't understand this, and the documentation doe
ethannicholas 2016/10/13 17:41:27 Added a comment explaining it.
45 fBlocks[from].fExits.insert(to);
46 fBlocks[to].fEntrances.insert(from);
47 }
48 }
49
50 void CFG::dump() {
51 for (size_t i = 0; i < fBlocks.size(); i++) {
52 printf("Block %d\n-------\nBefore: ", (int) i);
53 const char* separator = "";
54 for (auto iter = fBlocks[i].fBefore.begin(); iter != fBlocks[i].fBefore. end(); iter++) {
55 printf("%s%s = %s", separator, iter->first->description().c_str(),
56 iter->second ? iter->second->description().c_str() : "<undefi ned>");
57 separator = ", ";
58 }
59 printf("\nEntrances: ");
60 separator = "";
61 for (BlockId b : fBlocks[i].fEntrances) {
62 printf("%s%d", separator, (int) b);
63 separator = ", ";
64 }
65 printf("\n");
66 for (size_t j = 0; j < fBlocks[i].fNodes.size(); j++) {
67 printf("Node %d: %s\n", (int) j, fBlocks[i].fNodes[j].fNode->descrip tion().c_str());
68 }
69 printf("Exits: ");
70 separator = "";
71 for (BlockId b : fBlocks[i].fExits) {
72 printf("%s%d", separator, (int) b);
73 separator = ", ";
74 }
75 printf("\n\n");
76 }
77 }
78
79 void CFGGenerator::addExpression(CFG& cfg, const Expression* e) {
80 switch (e->fKind) {
81 case Expression::kBinary_Kind: {
82 const BinaryExpression* b = (const BinaryExpression*) e;
83 switch (b->fOperator) {
84 case Token::LOGICALAND: // fall through
85 case Token::LOGICALOR: {
86 // this isn't as precise as it could be -- we don't bother t o track that if we
87 // early exit from a logical and/or, we know which branch of an 'if' we're going
88 // to hit -- but it won't make much difference in practice.
89 this->addExpression(cfg, b->fLeft.get());
90 BlockId start = cfg.fCurrent;
91 cfg.newBlock();
92 this->addExpression(cfg, b->fRight.get());
93 cfg.addExit(start, cfg.fCurrent);
dogben 2016/10/13 03:55:42 Missing cfg.newBlock().
ethannicholas 2016/10/13 17:41:27 Fixed.
94 break;
95 }
96 case Token::EQ: {
97 this->addExpression(cfg, b->fRight.get());
98 this->addLValue(cfg, b->fLeft.get());
99 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({
100 BasicBlock::Node::kExpression_Kind,
101 b
102 });
103 break;
104 }
105 default:
106 this->addExpression(cfg, b->fLeft.get());
107 this->addExpression(cfg, b->fRight.get());
108 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({
109 BasicBlock::Node::kExpression_Kind,
110 b
111 });
112 }
113 break;
114 }
115 case Expression::kConstructor_Kind: {
116 const Constructor* c = (const Constructor*) e;
117 for (const auto& arg : c->fArguments) {
118 this->addExpression(cfg, arg.get());
119 }
120 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpr ession_Kind, c });
121 break;
122 }
123 case Expression::kFunctionCall_Kind: {
124 const FunctionCall* c = (const FunctionCall*) e;
125 for (const auto& arg : c->fArguments) {
126 this->addExpression(cfg, arg.get());
127 }
128 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpr ession_Kind, c });
129 break;
130 }
131 case Expression::kFieldAccess_Kind:
132 this->addExpression(cfg, ((const FieldAccess*) e)->fBase.get());
133 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpr ession_Kind, e });
134 break;
135 case Expression::kIndex_Kind:
136 this->addExpression(cfg, ((const IndexExpression*) e)->fIndex.get()) ;
dogben 2016/10/13 03:55:43 nit: Probably doesn't matter much, but SPIRV gener
ethannicholas 2016/10/13 17:41:27 Probably doesn't matter, but I fixed it anyway :-)
137 this->addExpression(cfg, ((const IndexExpression*) e)->fBase.get());
138 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpr ession_Kind, e });
139 break;
140 case Expression::kPrefix_Kind:
141 this->addExpression(cfg, ((const PrefixExpression*) e)->fOperand.get ());
142 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpr ession_Kind, e });
143 break;
144 case Expression::kPostfix_Kind:
145 this->addExpression(cfg, ((const PostfixExpression*) e)->fOperand.ge t());
146 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpr ession_Kind, e });
147 break;
148 case Expression::kSwizzle_Kind:
149 this->addExpression(cfg, ((const Swizzle*) e)->fBase.get());
150 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpr ession_Kind, e });
151 break;
152 case Expression::kBoolLiteral_Kind: // fall through
153 case Expression::kFloatLiteral_Kind: // fall through
154 case Expression::kIntLiteral_Kind: // fall through
155 case Expression::kVariableReference_Kind:
156 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpr ession_Kind, e });
157 break;
158 case Expression::kTernary_Kind: {
159 const TernaryExpression* t = (const TernaryExpression*) e;
160 this->addExpression(cfg, t->fTest.get());
161 BlockId start = cfg.fCurrent;
162 cfg.newBlock();
163 this->addExpression(cfg, t->fIfTrue.get());
164 BlockId next = cfg.newBlock();
165 cfg.fCurrent = start;
166 cfg.newBlock();
167 this->addExpression(cfg, t->fIfFalse.get());
168 cfg.addExit(cfg.fCurrent, next);
169 cfg.fCurrent = next;
170 break;
171 }
172 case Expression::kFunctionReference_Kind: // fall through
173 case Expression::kTypeReference_Kind: // fall through
174 case Expression::kDefined_Kind:
175 ASSERT(false);
176 break;
177 }
178 }
179
180 // adds expressions that are evaluated as part of resolving an lvalue
181 void CFGGenerator::addLValue(CFG& cfg, const Expression* e) {
182 switch (e->fKind) {
183 case Expression::kFieldAccess_Kind:
184 break;
dogben 2016/10/13 03:55:43 Need this->addLValue(cfg, ((const FieldAccess*) e)
ethannicholas 2016/10/13 17:41:27 I was initially thinking that would never do anyth
185 case Expression::kIndex_Kind:
186 this->addExpression(cfg, ((const IndexExpression*) e)->fIndex.get()) ;
dogben 2016/10/13 03:55:42 Need this->addLValue(cfg, ((const IndexExpression*
187 break;
188 case Expression::kSwizzle_Kind:
189 break;
dogben 2016/10/13 03:55:42 Need this->addLValue(cfg, ((const Swizzle*) e)->fB
190 case Expression::kVariableReference_Kind:
191 break;
192 default:
193 // not an lvalue, can't happen
194 ASSERT(false);
195 break;
196 }
197 }
198
199 void CFGGenerator::addStatement(CFG& cfg, const Statement* s) {
200 switch (s->fKind) {
201 case Statement::kBlock_Kind:
202 for (const auto& child : ((const Block*) s)->fStatements) {
203 addStatement(cfg, child.get());
204 }
205 break;
206 case Statement::kIf_Kind: {
207 const IfStatement* ifs = (const IfStatement*) s;
208 this->addExpression(cfg, ifs->fTest.get());
209 BlockId start = cfg.fCurrent;
210 cfg.newBlock();
211 this->addStatement(cfg, ifs->fIfTrue.get());
212 BlockId next = cfg.newBlock();
213 if (ifs->fIfFalse) {
214 cfg.fCurrent = start;
215 cfg.newBlock();
216 this->addStatement(cfg, ifs->fIfFalse.get());
217 cfg.addExit(cfg.fCurrent, next);
218 cfg.fCurrent = next;
219 } else {
220 cfg.addExit(start, next);
221 }
222 break;
223 }
224 case Statement::kExpression_Kind: {
225 this->addExpression(cfg, ((ExpressionStatement&) *s).fExpression.get ());
226 break;
227 }
228 case Statement::kVarDeclarations_Kind:
229 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kStat ement_Kind, s });
dogben 2016/10/13 03:55:43 Need addExpression for each variable's value.
ethannicholas 2016/10/13 17:41:27 Done.
230 break;
231 case Statement::kDiscard_Kind: // fall through
232 case Statement::kReturn_Kind:
233 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kStat ement_Kind, s });
dogben 2016/10/13 03:55:43 Need addExpression for return value.
ethannicholas 2016/10/13 17:41:27 Done.
234 cfg.fCurrent = cfg.newIsolatedBlock();
235 break;
236 case Statement::kBreak_Kind:
237 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kStat ement_Kind, s });
238 cfg.addExit(cfg.fCurrent, fLoopExits.top());
239 cfg.fCurrent = cfg.newIsolatedBlock();
240 break;
241 case Statement::kContinue_Kind:
242 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kStat ement_Kind, s });
243 cfg.addExit(cfg.fCurrent, fLoopContinues.top());
244 cfg.fCurrent = cfg.newIsolatedBlock();
245 break;
246 case Statement::kWhile_Kind: {
247 const WhileStatement* w = (const WhileStatement*) s;
248 BlockId loopStart = cfg.newBlock();
249 fLoopContinues.push(loopStart);
250 BlockId loopExit = cfg.newIsolatedBlock();
251 fLoopExits.push(loopExit);
252 this->addExpression(cfg, w->fTest.get());
253 BlockId test = cfg.fCurrent;
254 cfg.addExit(test, loopExit);
255 cfg.newBlock();
256 this->addStatement(cfg, w->fStatement.get());
257 cfg.addExit(cfg.fCurrent, loopStart);
258 fLoopContinues.pop();
259 fLoopExits.pop();
260 cfg.fCurrent = loopExit;
261 break;
262 }
263 case Statement::kDo_Kind: {
264 const DoStatement* d = (const DoStatement*) s;
265 BlockId loopStart = cfg.newBlock();
266 fLoopContinues.push(loopStart);
267 BlockId loopExit = cfg.newIsolatedBlock();
268 fLoopExits.push(loopExit);
269 this->addStatement(cfg, d->fStatement.get());
270 this->addExpression(cfg, d->fTest.get());
271 cfg.addExit(cfg.fCurrent, loopExit);
272 cfg.addExit(cfg.fCurrent, loopStart);
273 fLoopContinues.pop();
274 fLoopExits.pop();
275 cfg.fCurrent = loopExit;
276 break;
277 }
278 case Statement::kFor_Kind: {
279 const ForStatement* f = (const ForStatement*) s;
280 if (f->fInitializer) {
281 this->addStatement(cfg, f->fInitializer.get());
282 }
283 BlockId loopStart = cfg.newBlock();
284 BlockId next = cfg.newIsolatedBlock();
285 fLoopContinues.push(next);
286 BlockId loopExit = cfg.newIsolatedBlock();
287 fLoopExits.push(loopExit);
288 if (f->fTest) {
289 this->addExpression(cfg, f->fTest.get());
290 BlockId test = cfg.fCurrent;
291 cfg.addExit(test, loopExit);
292 }
293 cfg.newBlock();
294 this->addStatement(cfg, f->fStatement.get());
295 cfg.addExit(cfg.fCurrent, next);
296 cfg.fCurrent = next;
297 if (f->fNext) {
298 this->addExpression(cfg, f->fNext.get());
299 }
300 cfg.addExit(next, loopStart);
301 fLoopContinues.pop();
302 fLoopExits.pop();
303 cfg.fCurrent = loopExit;
304 break;
305 }
306 default:
307 printf("statement: %s\n", s->description().c_str());
308 ABORT("unsupported statement kind");
309 }
310 }
311
312 CFG CFGGenerator::getCFG(const FunctionDefinition& f) {
313 CFG result;
314 result.fStart = result.newBlock();
315 result.fCurrent = result.fStart;
316 this->addStatement(result, f.fBody.get());
317 result.newBlock();
318 result.fExit = result.fCurrent;
319 return result;
320 }
321
322 }
dogben 2016/10/13 03:55:43 nit: // namespace
ethannicholas 2016/10/13 17:41:27 Fixed.
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698