OLD | NEW |
---|---|
(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/SkSLReturnStatement.h" | |
22 #include "ir/SkSLSwizzle.h" | |
23 #include "ir/SkSLTernaryExpression.h" | |
24 #include "ir/SkSLVarDeclarationsStatement.h" | |
25 #include "ir/SkSLWhileStatement.h" | |
26 | |
27 namespace SkSL { | |
28 | |
29 BlockId CFG::newBlock() { | |
30 BlockId result = fBlocks.size(); | |
31 fBlocks.emplace_back(); | |
32 if (fBlocks.size() > 1) { | |
33 this->addExit(fCurrent, result); | |
34 } | |
35 fCurrent = result; | |
36 return result; | |
37 } | |
38 | |
39 BlockId CFG::newIsolatedBlock() { | |
40 BlockId result = fBlocks.size(); | |
41 fBlocks.emplace_back(); | |
42 return result; | |
43 } | |
44 | |
45 void CFG::addExit(BlockId from, BlockId to) { | |
46 if (from == 0 || fBlocks[from].fEntrances.size()) { | |
47 fBlocks[from].fExits.insert(to); | |
48 fBlocks[to].fEntrances.insert(from); | |
49 } | |
50 } | |
51 | |
52 void CFG::dump() { | |
53 for (size_t i = 0; i < fBlocks.size(); i++) { | |
54 printf("Block %d\n-------\nBefore: ", (int) i); | |
55 const char* separator = ""; | |
56 for (auto iter = fBlocks[i].fBefore.begin(); iter != fBlocks[i].fBefore. end(); iter++) { | |
57 printf("%s%s = %s", separator, iter->first->description().c_str(), | |
58 iter->second ? iter->second->description().c_str() : "<undefi ned>"); | |
59 separator = ", "; | |
60 } | |
61 printf("\nEntrances: "); | |
62 separator = ""; | |
63 for (BlockId b : fBlocks[i].fEntrances) { | |
64 printf("%s%d", separator, (int) b); | |
65 separator = ", "; | |
66 } | |
67 printf("\n"); | |
68 for (size_t j = 0; j < fBlocks[i].fNodes.size(); j++) { | |
69 printf("Node %d: %s\n", (int) j, fBlocks[i].fNodes[j].fNode->descrip tion().c_str()); | |
70 } | |
71 printf("Exits: "); | |
72 separator = ""; | |
73 for (BlockId b : fBlocks[i].fExits) { | |
74 printf("%s%d", separator, (int) b); | |
75 separator = ", "; | |
76 } | |
77 printf("\n\n"); | |
78 } | |
79 } | |
80 | |
81 void CFGGenerator::addExpression(CFG& cfg, const Expression* e) { | |
82 switch (e->fKind) { | |
83 case Expression::kBinary_Kind: { | |
84 const BinaryExpression* b = (const BinaryExpression*) e; | |
85 switch (b->fOperator) { | |
86 case Token::LOGICALAND: // fall through | |
87 case Token::LOGICALOR: { | |
88 // this isn't as precise as it could be -- we don't bother t o track that if we | |
89 // early exit from a logical and/or, we know which branch of an 'if' we're going | |
90 // to hit -- but it won't make much difference in practice. | |
91 this->addExpression(cfg, b->fLeft.get()); | |
92 BlockId start = cfg.fCurrent; | |
93 cfg.newBlock(); | |
94 this->addExpression(cfg, b->fRight.get()); | |
95 cfg.newBlock(); | |
96 cfg.addExit(start, cfg.fCurrent); | |
97 break; | |
98 } | |
99 case Token::EQ: { | |
100 this->addExpression(cfg, b->fRight.get()); | |
101 this->addLValue(cfg, b->fLeft.get()); | |
102 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ | |
103 BasicBlock::Node::kExpression_Kind, | |
104 b | |
105 }); | |
106 break; | |
107 } | |
108 default: | |
109 this->addExpression(cfg, b->fLeft.get()); | |
110 this->addExpression(cfg, b->fRight.get()); | |
111 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ | |
112 BasicBlock::Node::kExpression_Kind, | |
113 b | |
114 }); | |
115 } | |
116 break; | |
117 } | |
118 case Expression::kConstructor_Kind: { | |
119 const Constructor* c = (const Constructor*) e; | |
120 for (const auto& arg : c->fArguments) { | |
121 this->addExpression(cfg, arg.get()); | |
122 } | |
123 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpr ession_Kind, c }); | |
124 break; | |
125 } | |
126 case Expression::kFunctionCall_Kind: { | |
127 const FunctionCall* c = (const FunctionCall*) e; | |
128 for (const auto& arg : c->fArguments) { | |
129 this->addExpression(cfg, arg.get()); | |
130 } | |
131 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpr ession_Kind, c }); | |
132 break; | |
133 } | |
134 case Expression::kFieldAccess_Kind: | |
135 this->addExpression(cfg, ((const FieldAccess*) e)->fBase.get()); | |
136 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpr ession_Kind, e }); | |
137 break; | |
138 case Expression::kIndex_Kind: | |
139 this->addExpression(cfg, ((const IndexExpression*) e)->fBase.get()); | |
140 this->addExpression(cfg, ((const IndexExpression*) e)->fIndex.get()) ; | |
141 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpr ession_Kind, e }); | |
142 break; | |
143 case Expression::kPrefix_Kind: | |
144 this->addExpression(cfg, ((const PrefixExpression*) e)->fOperand.get ()); | |
145 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpr ession_Kind, e }); | |
146 break; | |
147 case Expression::kPostfix_Kind: | |
148 this->addExpression(cfg, ((const PostfixExpression*) e)->fOperand.ge t()); | |
149 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpr ession_Kind, e }); | |
150 break; | |
151 case Expression::kSwizzle_Kind: | |
152 this->addExpression(cfg, ((const Swizzle*) e)->fBase.get()); | |
153 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpr ession_Kind, e }); | |
154 break; | |
155 case Expression::kBoolLiteral_Kind: // fall through | |
156 case Expression::kFloatLiteral_Kind: // fall through | |
157 case Expression::kIntLiteral_Kind: // fall through | |
158 case Expression::kVariableReference_Kind: | |
159 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpr ession_Kind, e }); | |
160 break; | |
161 case Expression::kTernary_Kind: { | |
162 const TernaryExpression* t = (const TernaryExpression*) e; | |
163 this->addExpression(cfg, t->fTest.get()); | |
164 BlockId start = cfg.fCurrent; | |
165 cfg.newBlock(); | |
166 this->addExpression(cfg, t->fIfTrue.get()); | |
167 BlockId next = cfg.newBlock(); | |
168 cfg.fCurrent = start; | |
169 cfg.newBlock(); | |
170 this->addExpression(cfg, t->fIfFalse.get()); | |
171 cfg.addExit(cfg.fCurrent, next); | |
172 cfg.fCurrent = next; | |
173 break; | |
174 } | |
175 case Expression::kFunctionReference_Kind: // fall through | |
176 case Expression::kTypeReference_Kind: // fall through | |
177 case Expression::kDefined_Kind: | |
178 ASSERT(false); | |
179 break; | |
180 } | |
181 } | |
182 | |
183 // adds expressions that are evaluated as part of resolving an lvalue | |
184 void CFGGenerator::addLValue(CFG& cfg, const Expression* e) { | |
185 switch (e->fKind) { | |
186 case Expression::kFieldAccess_Kind: | |
187 this->addLValue(cfg, ((const FieldAccess*) e)->fBase.get()); | |
188 break; | |
189 case Expression::kIndex_Kind: | |
190 this->addLValue(cfg, ((const IndexExpression*) e)->fBase.get()); | |
191 this->addExpression(cfg, ((const IndexExpression*) e)->fIndex.get()) ; | |
192 break; | |
193 case Expression::kSwizzle_Kind: | |
194 this->addLValue(cfg, ((const Swizzle*) e)->fBase.get()); | |
195 break; | |
196 case Expression::kVariableReference_Kind: | |
197 break; | |
198 default: | |
199 // not an lvalue, can't happen | |
200 ASSERT(false); | |
201 break; | |
202 } | |
203 } | |
204 | |
205 void CFGGenerator::addStatement(CFG& cfg, const Statement* s) { | |
206 switch (s->fKind) { | |
207 case Statement::kBlock_Kind: | |
208 for (const auto& child : ((const Block*) s)->fStatements) { | |
209 addStatement(cfg, child.get()); | |
210 } | |
211 break; | |
212 case Statement::kIf_Kind: { | |
213 const IfStatement* ifs = (const IfStatement*) s; | |
214 this->addExpression(cfg, ifs->fTest.get()); | |
215 BlockId start = cfg.fCurrent; | |
216 cfg.newBlock(); | |
217 this->addStatement(cfg, ifs->fIfTrue.get()); | |
218 BlockId next = cfg.newBlock(); | |
219 if (ifs->fIfFalse) { | |
220 cfg.fCurrent = start; | |
221 cfg.newBlock(); | |
222 this->addStatement(cfg, ifs->fIfFalse.get()); | |
223 cfg.addExit(cfg.fCurrent, next); | |
224 cfg.fCurrent = next; | |
225 } else { | |
226 cfg.addExit(start, next); | |
227 } | |
228 break; | |
229 } | |
230 case Statement::kExpression_Kind: { | |
231 this->addExpression(cfg, ((ExpressionStatement&) *s).fExpression.get ()); | |
232 break; | |
233 } | |
234 case Statement::kVarDeclarations_Kind: { | |
235 const VarDeclarationsStatement& decls = ((VarDeclarationsStatement&) *s); | |
236 for (const auto& vd : decls.fDeclaration->fVars) { | |
237 if (vd.fValue) { | |
238 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ | |
239 BasicBlock::Node::kExpression_Kind, | |
240 vd.fValue.get() | |
dogben
2016/10/13 19:12:43
I'm pretty sure you need this->addExpression(cfg,
ethannicholas
2016/10/13 19:42:06
I have absolutely no idea what I was thinking ther
| |
241 }); | |
242 } | |
243 } | |
244 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kStat ement_Kind, s }); | |
245 break; | |
246 } | |
247 case Statement::kDiscard_Kind: | |
248 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kStat ement_Kind, s }); | |
249 cfg.fCurrent = cfg.newIsolatedBlock(); | |
250 break; | |
251 case Statement::kReturn_Kind: { | |
252 const ReturnStatement& r = ((ReturnStatement&) *s); | |
253 if (r.fExpression) { | |
254 this->addExpression(cfg, r.fExpression.get()); | |
255 } | |
256 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kStat ement_Kind, s }); | |
257 cfg.fCurrent = cfg.newIsolatedBlock(); | |
258 break; | |
259 } | |
260 case Statement::kBreak_Kind: | |
261 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kStat ement_Kind, s }); | |
262 cfg.addExit(cfg.fCurrent, fLoopExits.top()); | |
263 cfg.fCurrent = cfg.newIsolatedBlock(); | |
264 break; | |
265 case Statement::kContinue_Kind: | |
266 cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kStat ement_Kind, s }); | |
267 cfg.addExit(cfg.fCurrent, fLoopContinues.top()); | |
268 cfg.fCurrent = cfg.newIsolatedBlock(); | |
269 break; | |
270 case Statement::kWhile_Kind: { | |
271 const WhileStatement* w = (const WhileStatement*) s; | |
272 BlockId loopStart = cfg.newBlock(); | |
273 fLoopContinues.push(loopStart); | |
274 BlockId loopExit = cfg.newIsolatedBlock(); | |
275 fLoopExits.push(loopExit); | |
276 this->addExpression(cfg, w->fTest.get()); | |
277 BlockId test = cfg.fCurrent; | |
278 cfg.addExit(test, loopExit); | |
279 cfg.newBlock(); | |
280 this->addStatement(cfg, w->fStatement.get()); | |
281 cfg.addExit(cfg.fCurrent, loopStart); | |
282 fLoopContinues.pop(); | |
283 fLoopExits.pop(); | |
284 cfg.fCurrent = loopExit; | |
285 break; | |
286 } | |
287 case Statement::kDo_Kind: { | |
288 const DoStatement* d = (const DoStatement*) s; | |
289 BlockId loopStart = cfg.newBlock(); | |
290 fLoopContinues.push(loopStart); | |
291 BlockId loopExit = cfg.newIsolatedBlock(); | |
292 fLoopExits.push(loopExit); | |
293 this->addStatement(cfg, d->fStatement.get()); | |
294 this->addExpression(cfg, d->fTest.get()); | |
295 cfg.addExit(cfg.fCurrent, loopExit); | |
296 cfg.addExit(cfg.fCurrent, loopStart); | |
297 fLoopContinues.pop(); | |
298 fLoopExits.pop(); | |
299 cfg.fCurrent = loopExit; | |
300 break; | |
301 } | |
302 case Statement::kFor_Kind: { | |
303 const ForStatement* f = (const ForStatement*) s; | |
304 if (f->fInitializer) { | |
305 this->addStatement(cfg, f->fInitializer.get()); | |
306 } | |
307 BlockId loopStart = cfg.newBlock(); | |
308 BlockId next = cfg.newIsolatedBlock(); | |
309 fLoopContinues.push(next); | |
310 BlockId loopExit = cfg.newIsolatedBlock(); | |
311 fLoopExits.push(loopExit); | |
312 if (f->fTest) { | |
313 this->addExpression(cfg, f->fTest.get()); | |
314 BlockId test = cfg.fCurrent; | |
315 cfg.addExit(test, loopExit); | |
316 } | |
317 cfg.newBlock(); | |
318 this->addStatement(cfg, f->fStatement.get()); | |
319 cfg.addExit(cfg.fCurrent, next); | |
320 cfg.fCurrent = next; | |
321 if (f->fNext) { | |
322 this->addExpression(cfg, f->fNext.get()); | |
323 } | |
324 cfg.addExit(next, loopStart); | |
325 fLoopContinues.pop(); | |
326 fLoopExits.pop(); | |
327 cfg.fCurrent = loopExit; | |
328 break; | |
329 } | |
330 default: | |
331 printf("statement: %s\n", s->description().c_str()); | |
332 ABORT("unsupported statement kind"); | |
333 } | |
334 } | |
335 | |
336 CFG CFGGenerator::getCFG(const FunctionDefinition& f) { | |
337 CFG result; | |
338 result.fStart = result.newBlock(); | |
339 result.fCurrent = result.fStart; | |
340 this->addStatement(result, f.fBody.get()); | |
341 result.newBlock(); | |
342 result.fExit = result.fCurrent; | |
343 return result; | |
344 } | |
345 | |
346 } // namespace | |
OLD | NEW |