123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664 |
- /*
- * Copyright 2016 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
- #include "src/sksl/SkSLCFGGenerator.h"
- #include "src/sksl/ir/SkSLBinaryExpression.h"
- #include "src/sksl/ir/SkSLConstructor.h"
- #include "src/sksl/ir/SkSLDoStatement.h"
- #include "src/sksl/ir/SkSLExpressionStatement.h"
- #include "src/sksl/ir/SkSLExternalFunctionCall.h"
- #include "src/sksl/ir/SkSLFieldAccess.h"
- #include "src/sksl/ir/SkSLForStatement.h"
- #include "src/sksl/ir/SkSLFunctionCall.h"
- #include "src/sksl/ir/SkSLIfStatement.h"
- #include "src/sksl/ir/SkSLIndexExpression.h"
- #include "src/sksl/ir/SkSLPostfixExpression.h"
- #include "src/sksl/ir/SkSLPrefixExpression.h"
- #include "src/sksl/ir/SkSLReturnStatement.h"
- #include "src/sksl/ir/SkSLSwitchStatement.h"
- #include "src/sksl/ir/SkSLSwizzle.h"
- #include "src/sksl/ir/SkSLTernaryExpression.h"
- #include "src/sksl/ir/SkSLVarDeclarationsStatement.h"
- #include "src/sksl/ir/SkSLWhileStatement.h"
- namespace SkSL {
- BlockId CFG::newBlock() {
- BlockId result = fBlocks.size();
- fBlocks.emplace_back();
- if (fBlocks.size() > 1) {
- this->addExit(fCurrent, result);
- }
- fCurrent = result;
- return result;
- }
- BlockId CFG::newIsolatedBlock() {
- BlockId result = fBlocks.size();
- fBlocks.emplace_back();
- return result;
- }
- void CFG::addExit(BlockId from, BlockId to) {
- if (from == 0 || fBlocks[from].fEntrances.size()) {
- fBlocks[from].fExits.insert(to);
- fBlocks[to].fEntrances.insert(from);
- }
- }
- void CFG::dump() {
- for (size_t i = 0; i < fBlocks.size(); i++) {
- printf("Block %d\n-------\nBefore: ", (int) i);
- const char* separator = "";
- for (auto iter = fBlocks[i].fBefore.begin(); iter != fBlocks[i].fBefore.end(); iter++) {
- printf("%s%s = %s", separator, iter->first->description().c_str(),
- iter->second ? (*iter->second)->description().c_str() : "<undefined>");
- separator = ", ";
- }
- printf("\nEntrances: ");
- separator = "";
- for (BlockId b : fBlocks[i].fEntrances) {
- printf("%s%d", separator, (int) b);
- separator = ", ";
- }
- printf("\n");
- for (size_t j = 0; j < fBlocks[i].fNodes.size(); j++) {
- BasicBlock::Node& n = fBlocks[i].fNodes[j];
- printf("Node %d (%p): %s\n", (int) j, &n, n.fKind == BasicBlock::Node::kExpression_Kind
- ? (*n.expression())->description().c_str()
- : (*n.statement())->description().c_str());
- }
- printf("Exits: ");
- separator = "";
- for (BlockId b : fBlocks[i].fExits) {
- printf("%s%d", separator, (int) b);
- separator = ", ";
- }
- printf("\n\n");
- }
- }
- bool BasicBlock::tryRemoveExpressionBefore(std::vector<BasicBlock::Node>::iterator* iter,
- Expression* e) {
- if (e->fKind == Expression::kTernary_Kind) {
- return false;
- }
- bool result;
- if ((*iter)->fKind == BasicBlock::Node::kExpression_Kind) {
- SkASSERT((*iter)->expression()->get() != e);
- Expression* old = (*iter)->expression()->get();
- do {
- if ((*iter) == fNodes.begin()) {
- return false;
- }
- --(*iter);
- } while ((*iter)->fKind != BasicBlock::Node::kExpression_Kind ||
- (*iter)->expression()->get() != e);
- result = this->tryRemoveExpression(iter);
- while ((*iter)->fKind != BasicBlock::Node::kExpression_Kind ||
- (*iter)->expression()->get() != old) {
- SkASSERT(*iter != fNodes.end());
- ++(*iter);
- }
- } else {
- Statement* old = (*iter)->statement()->get();
- do {
- if ((*iter) == fNodes.begin()) {
- return false;
- }
- --(*iter);
- } while ((*iter)->fKind != BasicBlock::Node::kExpression_Kind ||
- (*iter)->expression()->get() != e);
- result = this->tryRemoveExpression(iter);
- while ((*iter)->fKind != BasicBlock::Node::kStatement_Kind ||
- (*iter)->statement()->get() != old) {
- SkASSERT(*iter != fNodes.end());
- ++(*iter);
- }
- }
- return result;
- }
- bool BasicBlock::tryRemoveLValueBefore(std::vector<BasicBlock::Node>::iterator* iter,
- Expression* lvalue) {
- switch (lvalue->fKind) {
- case Expression::kExternalValue_Kind: // fall through
- case Expression::kVariableReference_Kind:
- return true;
- case Expression::kSwizzle_Kind:
- return this->tryRemoveLValueBefore(iter, ((Swizzle*) lvalue)->fBase.get());
- case Expression::kFieldAccess_Kind:
- return this->tryRemoveLValueBefore(iter, ((FieldAccess*) lvalue)->fBase.get());
- case Expression::kIndex_Kind:
- if (!this->tryRemoveLValueBefore(iter, ((IndexExpression*) lvalue)->fBase.get())) {
- return false;
- }
- return this->tryRemoveExpressionBefore(iter, ((IndexExpression*) lvalue)->fIndex.get());
- case Expression::kTernary_Kind:
- if (!this->tryRemoveExpressionBefore(iter,
- ((TernaryExpression*) lvalue)->fTest.get())) {
- return false;
- }
- if (!this->tryRemoveLValueBefore(iter, ((TernaryExpression*) lvalue)->fIfTrue.get())) {
- return false;
- }
- return this->tryRemoveLValueBefore(iter, ((TernaryExpression*) lvalue)->fIfFalse.get());
- default:
- ABORT("invalid lvalue: %s\n", lvalue->description().c_str());
- }
- }
- bool BasicBlock::tryRemoveExpression(std::vector<BasicBlock::Node>::iterator* iter) {
- Expression* expr = (*iter)->expression()->get();
- switch (expr->fKind) {
- case Expression::kBinary_Kind: {
- BinaryExpression* b = (BinaryExpression*) expr;
- if (b->fOperator == Token::EQ) {
- if (!this->tryRemoveLValueBefore(iter, b->fLeft.get())) {
- return false;
- }
- } else if (!this->tryRemoveExpressionBefore(iter, b->fLeft.get())) {
- return false;
- }
- if (!this->tryRemoveExpressionBefore(iter, b->fRight.get())) {
- return false;
- }
- SkASSERT((*iter)->expression()->get() == expr);
- *iter = fNodes.erase(*iter);
- return true;
- }
- case Expression::kTernary_Kind: {
- // ternaries cross basic block boundaries, must regenerate the CFG to remove it
- return false;
- }
- case Expression::kFieldAccess_Kind: {
- FieldAccess* f = (FieldAccess*) expr;
- if (!this->tryRemoveExpressionBefore(iter, f->fBase.get())) {
- return false;
- }
- *iter = fNodes.erase(*iter);
- return true;
- }
- case Expression::kSwizzle_Kind: {
- Swizzle* s = (Swizzle*) expr;
- if (!this->tryRemoveExpressionBefore(iter, s->fBase.get())) {
- return false;
- }
- *iter = fNodes.erase(*iter);
- return true;
- }
- case Expression::kIndex_Kind: {
- IndexExpression* idx = (IndexExpression*) expr;
- if (!this->tryRemoveExpressionBefore(iter, idx->fBase.get())) {
- return false;
- }
- if (!this->tryRemoveExpressionBefore(iter, idx->fIndex.get())) {
- return false;
- }
- *iter = fNodes.erase(*iter);
- return true;
- }
- case Expression::kConstructor_Kind: {
- Constructor* c = (Constructor*) expr;
- for (auto& arg : c->fArguments) {
- if (!this->tryRemoveExpressionBefore(iter, arg.get())) {
- return false;
- }
- SkASSERT((*iter)->expression()->get() == expr);
- }
- *iter = fNodes.erase(*iter);
- return true;
- }
- case Expression::kFunctionCall_Kind: {
- FunctionCall* f = (FunctionCall*) expr;
- for (auto& arg : f->fArguments) {
- if (!this->tryRemoveExpressionBefore(iter, arg.get())) {
- return false;
- }
- SkASSERT((*iter)->expression()->get() == expr);
- }
- *iter = fNodes.erase(*iter);
- return true;
- }
- case Expression::kPrefix_Kind:
- if (!this->tryRemoveExpressionBefore(iter,
- ((PrefixExpression*) expr)->fOperand.get())) {
- return false;
- }
- *iter = fNodes.erase(*iter);
- return true;
- case Expression::kPostfix_Kind:
- if (!this->tryRemoveExpressionBefore(iter,
- ((PrefixExpression*) expr)->fOperand.get())) {
- return false;
- }
- *iter = fNodes.erase(*iter);
- return true;
- case Expression::kBoolLiteral_Kind: // fall through
- case Expression::kFloatLiteral_Kind: // fall through
- case Expression::kIntLiteral_Kind: // fall through
- case Expression::kSetting_Kind: // fall through
- case Expression::kVariableReference_Kind:
- *iter = fNodes.erase(*iter);
- return true;
- default:
- ABORT("unhandled expression: %s\n", expr->description().c_str());
- }
- }
- bool BasicBlock::tryInsertExpression(std::vector<BasicBlock::Node>::iterator* iter,
- std::unique_ptr<Expression>* expr) {
- switch ((*expr)->fKind) {
- case Expression::kBinary_Kind: {
- BinaryExpression* b = (BinaryExpression*) expr->get();
- if (!this->tryInsertExpression(iter, &b->fRight)) {
- return false;
- }
- ++(*iter);
- if (!this->tryInsertExpression(iter, &b->fLeft)) {
- return false;
- }
- ++(*iter);
- BasicBlock::Node node = { BasicBlock::Node::kExpression_Kind, true, expr, nullptr };
- *iter = fNodes.insert(*iter, node);
- return true;
- }
- case Expression::kBoolLiteral_Kind: // fall through
- case Expression::kFloatLiteral_Kind: // fall through
- case Expression::kIntLiteral_Kind: // fall through
- case Expression::kVariableReference_Kind: {
- BasicBlock::Node node = { BasicBlock::Node::kExpression_Kind, true, expr, nullptr };
- *iter = fNodes.insert(*iter, node);
- return true;
- }
- case Expression::kConstructor_Kind: {
- Constructor* c = (Constructor*) expr->get();
- for (auto& arg : c->fArguments) {
- if (!this->tryInsertExpression(iter, &arg)) {
- return false;
- }
- ++(*iter);
- }
- BasicBlock::Node node = { BasicBlock::Node::kExpression_Kind, true, expr, nullptr };
- *iter = fNodes.insert(*iter, node);
- return true;
- }
- default:
- return false;
- }
- }
- void CFGGenerator::addExpression(CFG& cfg, std::unique_ptr<Expression>* e, bool constantPropagate) {
- SkASSERT(e);
- switch ((*e)->fKind) {
- case Expression::kBinary_Kind: {
- BinaryExpression* b = (BinaryExpression*) e->get();
- switch (b->fOperator) {
- case Token::LOGICALAND: // fall through
- case Token::LOGICALOR: {
- // this isn't as precise as it could be -- we don't bother to track that if we
- // early exit from a logical and/or, we know which branch of an 'if' we're going
- // to hit -- but it won't make much difference in practice.
- this->addExpression(cfg, &b->fLeft, constantPropagate);
- BlockId start = cfg.fCurrent;
- cfg.newBlock();
- this->addExpression(cfg, &b->fRight, constantPropagate);
- cfg.newBlock();
- cfg.addExit(start, cfg.fCurrent);
- cfg.fBlocks[cfg.fCurrent].fNodes.push_back({
- BasicBlock::Node::kExpression_Kind,
- constantPropagate,
- e,
- nullptr
- });
- break;
- }
- case Token::EQ: {
- this->addExpression(cfg, &b->fRight, constantPropagate);
- this->addLValue(cfg, &b->fLeft);
- cfg.fBlocks[cfg.fCurrent].fNodes.push_back({
- BasicBlock::Node::kExpression_Kind,
- constantPropagate,
- e,
- nullptr
- });
- break;
- }
- default:
- this->addExpression(cfg, &b->fLeft, !Compiler::IsAssignment(b->fOperator));
- this->addExpression(cfg, &b->fRight, constantPropagate);
- cfg.fBlocks[cfg.fCurrent].fNodes.push_back({
- BasicBlock::Node::kExpression_Kind,
- constantPropagate,
- e,
- nullptr
- });
- }
- break;
- }
- case Expression::kConstructor_Kind: {
- Constructor* c = (Constructor*) e->get();
- for (auto& arg : c->fArguments) {
- this->addExpression(cfg, &arg, constantPropagate);
- }
- cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpression_Kind,
- constantPropagate, e, nullptr });
- break;
- }
- case Expression::kExternalFunctionCall_Kind: {
- ExternalFunctionCall* c = (ExternalFunctionCall*) e->get();
- for (auto& arg : c->fArguments) {
- this->addExpression(cfg, &arg, constantPropagate);
- }
- cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpression_Kind,
- constantPropagate, e, nullptr });
- break;
- }
- case Expression::kFunctionCall_Kind: {
- FunctionCall* c = (FunctionCall*) e->get();
- for (auto& arg : c->fArguments) {
- this->addExpression(cfg, &arg, constantPropagate);
- }
- cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpression_Kind,
- constantPropagate, e, nullptr });
- break;
- }
- case Expression::kFieldAccess_Kind:
- this->addExpression(cfg, &((FieldAccess*) e->get())->fBase, constantPropagate);
- cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpression_Kind,
- constantPropagate, e, nullptr });
- break;
- case Expression::kIndex_Kind:
- this->addExpression(cfg, &((IndexExpression*) e->get())->fBase, constantPropagate);
- this->addExpression(cfg, &((IndexExpression*) e->get())->fIndex, constantPropagate);
- cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpression_Kind,
- constantPropagate, e, nullptr });
- break;
- case Expression::kPrefix_Kind: {
- PrefixExpression* p = (PrefixExpression*) e->get();
- this->addExpression(cfg, &p->fOperand, constantPropagate &&
- p->fOperator != Token::PLUSPLUS &&
- p->fOperator != Token::MINUSMINUS);
- cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpression_Kind,
- constantPropagate, e, nullptr });
- break;
- }
- case Expression::kPostfix_Kind:
- this->addExpression(cfg, &((PostfixExpression*) e->get())->fOperand, false);
- cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpression_Kind,
- constantPropagate, e, nullptr });
- break;
- case Expression::kSwizzle_Kind:
- this->addExpression(cfg, &((Swizzle*) e->get())->fBase, constantPropagate);
- cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpression_Kind,
- constantPropagate, e, nullptr });
- break;
- case Expression::kAppendStage_Kind: // fall through
- case Expression::kBoolLiteral_Kind: // fall through
- case Expression::kExternalValue_Kind: // fall through
- case Expression::kFloatLiteral_Kind: // fall through
- case Expression::kIntLiteral_Kind: // fall through
- case Expression::kNullLiteral_Kind: // fall through
- case Expression::kSetting_Kind: // fall through
- case Expression::kVariableReference_Kind:
- cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpression_Kind,
- constantPropagate, e, nullptr });
- break;
- case Expression::kTernary_Kind: {
- TernaryExpression* t = (TernaryExpression*) e->get();
- this->addExpression(cfg, &t->fTest, constantPropagate);
- cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpression_Kind,
- constantPropagate, e, nullptr });
- BlockId start = cfg.fCurrent;
- cfg.newBlock();
- this->addExpression(cfg, &t->fIfTrue, constantPropagate);
- BlockId next = cfg.newBlock();
- cfg.fCurrent = start;
- cfg.newBlock();
- this->addExpression(cfg, &t->fIfFalse, constantPropagate);
- cfg.addExit(cfg.fCurrent, next);
- cfg.fCurrent = next;
- break;
- }
- case Expression::kFunctionReference_Kind: // fall through
- case Expression::kTypeReference_Kind: // fall through
- case Expression::kDefined_Kind:
- SkASSERT(false);
- break;
- }
- }
- // adds expressions that are evaluated as part of resolving an lvalue
- void CFGGenerator::addLValue(CFG& cfg, std::unique_ptr<Expression>* e) {
- switch ((*e)->fKind) {
- case Expression::kFieldAccess_Kind:
- this->addLValue(cfg, &((FieldAccess&) **e).fBase);
- break;
- case Expression::kIndex_Kind:
- this->addLValue(cfg, &((IndexExpression&) **e).fBase);
- this->addExpression(cfg, &((IndexExpression&) **e).fIndex, true);
- break;
- case Expression::kSwizzle_Kind:
- this->addLValue(cfg, &((Swizzle&) **e).fBase);
- break;
- case Expression::kExternalValue_Kind: // fall through
- case Expression::kVariableReference_Kind:
- break;
- case Expression::kTernary_Kind:
- this->addExpression(cfg, &((TernaryExpression&) **e).fTest, true);
- // Technically we will of course only evaluate one or the other, but if the test turns
- // out to be constant, the ternary will get collapsed down to just one branch anyway. So
- // it should be ok to pretend that we always evaluate both branches here.
- this->addLValue(cfg, &((TernaryExpression&) **e).fIfTrue);
- this->addLValue(cfg, &((TernaryExpression&) **e).fIfFalse);
- break;
- default:
- // not an lvalue, can't happen
- SkASSERT(false);
- break;
- }
- }
- static bool is_true(Expression& expr) {
- return expr.fKind == Expression::kBoolLiteral_Kind && ((BoolLiteral&) expr).fValue;
- }
- void CFGGenerator::addStatement(CFG& cfg, std::unique_ptr<Statement>* s) {
- switch ((*s)->fKind) {
- case Statement::kBlock_Kind:
- for (auto& child : ((Block&) **s).fStatements) {
- addStatement(cfg, &child);
- }
- break;
- case Statement::kIf_Kind: {
- IfStatement& ifs = (IfStatement&) **s;
- this->addExpression(cfg, &ifs.fTest, true);
- cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kStatement_Kind, false,
- nullptr, s });
- BlockId start = cfg.fCurrent;
- cfg.newBlock();
- this->addStatement(cfg, &ifs.fIfTrue);
- BlockId next = cfg.newBlock();
- if (ifs.fIfFalse) {
- cfg.fCurrent = start;
- cfg.newBlock();
- this->addStatement(cfg, &ifs.fIfFalse);
- cfg.addExit(cfg.fCurrent, next);
- cfg.fCurrent = next;
- } else {
- cfg.addExit(start, next);
- }
- break;
- }
- case Statement::kExpression_Kind: {
- this->addExpression(cfg, &((ExpressionStatement&) **s).fExpression, true);
- cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kStatement_Kind, false,
- nullptr, s });
- break;
- }
- case Statement::kVarDeclarations_Kind: {
- VarDeclarationsStatement& decls = ((VarDeclarationsStatement&) **s);
- for (auto& stmt : decls.fDeclaration->fVars) {
- if (stmt->fKind == Statement::kNop_Kind) {
- continue;
- }
- VarDeclaration& vd = (VarDeclaration&) *stmt;
- if (vd.fValue) {
- this->addExpression(cfg, &vd.fValue, true);
- }
- cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kStatement_Kind,
- false, nullptr, &stmt });
- }
- cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kStatement_Kind, false,
- nullptr, s });
- break;
- }
- case Statement::kDiscard_Kind:
- cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kStatement_Kind, false,
- nullptr, s });
- cfg.fCurrent = cfg.newIsolatedBlock();
- break;
- case Statement::kReturn_Kind: {
- ReturnStatement& r = ((ReturnStatement&) **s);
- if (r.fExpression) {
- this->addExpression(cfg, &r.fExpression, true);
- }
- cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kStatement_Kind, false,
- nullptr, s });
- cfg.fCurrent = cfg.newIsolatedBlock();
- break;
- }
- case Statement::kBreak_Kind:
- cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kStatement_Kind, false,
- nullptr, s });
- cfg.addExit(cfg.fCurrent, fLoopExits.top());
- cfg.fCurrent = cfg.newIsolatedBlock();
- break;
- case Statement::kContinue_Kind:
- cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kStatement_Kind, false,
- nullptr, s });
- cfg.addExit(cfg.fCurrent, fLoopContinues.top());
- cfg.fCurrent = cfg.newIsolatedBlock();
- break;
- case Statement::kWhile_Kind: {
- WhileStatement& w = (WhileStatement&) **s;
- BlockId loopStart = cfg.newBlock();
- fLoopContinues.push(loopStart);
- BlockId loopExit = cfg.newIsolatedBlock();
- fLoopExits.push(loopExit);
- this->addExpression(cfg, &w.fTest, true);
- BlockId test = cfg.fCurrent;
- if (!is_true(*w.fTest)) {
- cfg.addExit(test, loopExit);
- }
- cfg.newBlock();
- this->addStatement(cfg, &w.fStatement);
- cfg.addExit(cfg.fCurrent, loopStart);
- fLoopContinues.pop();
- fLoopExits.pop();
- cfg.fCurrent = loopExit;
- break;
- }
- case Statement::kDo_Kind: {
- DoStatement& d = (DoStatement&) **s;
- BlockId loopStart = cfg.newBlock();
- fLoopContinues.push(loopStart);
- BlockId loopExit = cfg.newIsolatedBlock();
- fLoopExits.push(loopExit);
- this->addStatement(cfg, &d.fStatement);
- this->addExpression(cfg, &d.fTest, true);
- cfg.addExit(cfg.fCurrent, loopExit);
- cfg.addExit(cfg.fCurrent, loopStart);
- fLoopContinues.pop();
- fLoopExits.pop();
- cfg.fCurrent = loopExit;
- break;
- }
- case Statement::kFor_Kind: {
- ForStatement& f = (ForStatement&) **s;
- if (f.fInitializer) {
- this->addStatement(cfg, &f.fInitializer);
- }
- BlockId loopStart = cfg.newBlock();
- BlockId next = cfg.newIsolatedBlock();
- fLoopContinues.push(next);
- BlockId loopExit = cfg.newIsolatedBlock();
- fLoopExits.push(loopExit);
- if (f.fTest) {
- this->addExpression(cfg, &f.fTest, true);
- // this isn't quite right; we should have an exit from here to the loop exit, and
- // remove the exit from the loop body to the loop exit. Structuring it like this
- // forces the optimizer to believe that the loop body is always executed at least
- // once. While not strictly correct, this avoids incorrect "variable not assigned"
- // errors on variables which are assigned within the loop. The correct solution to
- // this is to analyze the loop to see whether or not at least one iteration is
- // guaranteed to happen, but for the time being we take the easy way out.
- }
- cfg.newBlock();
- this->addStatement(cfg, &f.fStatement);
- cfg.addExit(cfg.fCurrent, next);
- cfg.fCurrent = next;
- if (f.fNext) {
- this->addExpression(cfg, &f.fNext, true);
- }
- cfg.addExit(cfg.fCurrent, loopStart);
- cfg.addExit(cfg.fCurrent, loopExit);
- fLoopContinues.pop();
- fLoopExits.pop();
- cfg.fCurrent = loopExit;
- break;
- }
- case Statement::kSwitch_Kind: {
- SwitchStatement& ss = (SwitchStatement&) **s;
- this->addExpression(cfg, &ss.fValue, true);
- cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kStatement_Kind, false,
- nullptr, s });
- BlockId start = cfg.fCurrent;
- BlockId switchExit = cfg.newIsolatedBlock();
- fLoopExits.push(switchExit);
- for (const auto& c : ss.fCases) {
- cfg.newBlock();
- cfg.addExit(start, cfg.fCurrent);
- if (c->fValue) {
- // technically this should go in the start block, but it doesn't actually matter
- // because it must be constant. Not worth running two loops for.
- this->addExpression(cfg, &c->fValue, true);
- }
- for (auto& caseStatement : c->fStatements) {
- this->addStatement(cfg, &caseStatement);
- }
- }
- cfg.addExit(cfg.fCurrent, switchExit);
- // note that unlike GLSL, our grammar requires the default case to be last
- if (0 == ss.fCases.size() || ss.fCases[ss.fCases.size() - 1]->fValue) {
- // switch does not have a default clause, mark that it can skip straight to the end
- cfg.addExit(start, switchExit);
- }
- fLoopExits.pop();
- cfg.fCurrent = switchExit;
- break;
- }
- case Statement::kNop_Kind:
- break;
- default:
- printf("statement: %s\n", (*s)->description().c_str());
- ABORT("unsupported statement kind");
- }
- }
- CFG CFGGenerator::getCFG(FunctionDefinition& f) {
- CFG result;
- result.fStart = result.newBlock();
- result.fCurrent = result.fStart;
- this->addStatement(result, &f.fBody);
- result.newBlock();
- result.fExit = result.fCurrent;
- return result;
- }
- } // namespace
|