LCOV - code coverage report
Current view: top level - gfx/skia/skia/src/sksl - SkSLCFGGenerator.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 260 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 8 0.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13