Chromium Code Reviews| 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/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.
| |
| OLD | NEW |