From cb67096b61f699b047fe8635984db1ac708a7b99 Mon Sep 17 00:00:00 2001 From: Ethan Nicholas Date: Thu, 20 Apr 2017 19:31:52 -0400 Subject: Improved skslc optimizer, particularly around vectors. BUG=skia: Change-Id: Idb364d9198f2ff84aad1eb68e236fb45ec1c86b7 Reviewed-on: https://skia-review.googlesource.com/8000 Commit-Queue: Ethan Nicholas Reviewed-by: Ben Wagner --- src/sksl/SkSLCFGGenerator.cpp | 291 +++++++++++++++++--- src/sksl/SkSLCFGGenerator.h | 77 +++++- src/sksl/SkSLCompiler.cpp | 368 ++++++++++++++++++++++--- src/sksl/SkSLCompiler.h | 27 +- src/sksl/SkSLContext.h | 4 + src/sksl/SkSLGLSLCodeGenerator.cpp | 39 +-- src/sksl/SkSLGLSLCodeGenerator.h | 2 + src/sksl/SkSLIRGenerator.cpp | 72 +++-- src/sksl/SkSLParser.cpp | 10 +- src/sksl/SkSLSPIRVCodeGenerator.cpp | 12 +- src/sksl/SkSLToken.h | 1 + src/sksl/ast/SkSLASTFunction.h | 6 +- src/sksl/ir/SkSLBinaryExpression.h | 12 +- src/sksl/ir/SkSLBlock.h | 11 +- src/sksl/ir/SkSLBoolLiteral.h | 4 + src/sksl/ir/SkSLConstructor.h | 73 ++++- src/sksl/ir/SkSLDoStatement.h | 2 +- src/sksl/ir/SkSLExpression.h | 7 + src/sksl/ir/SkSLFieldAccess.h | 6 +- src/sksl/ir/SkSLFloatLiteral.h | 11 +- src/sksl/ir/SkSLForStatement.h | 4 +- src/sksl/ir/SkSLFunctionCall.h | 9 + src/sksl/ir/SkSLFunctionDeclaration.h | 4 +- src/sksl/ir/SkSLFunctionDefinition.h | 4 +- src/sksl/ir/SkSLFunctionReference.h | 6 +- src/sksl/ir/SkSLIfStatement.h | 5 +- src/sksl/ir/SkSLIndexExpression.h | 4 + src/sksl/ir/SkSLIntLiteral.h | 8 +- src/sksl/ir/SkSLModifiers.h | 34 +-- src/sksl/ir/SkSLNop.h | 36 +++ src/sksl/ir/SkSLPostfixExpression.h | 6 +- src/sksl/ir/SkSLPrefixExpression.h | 24 +- src/sksl/ir/SkSLStatement.h | 6 + src/sksl/ir/SkSLSwizzle.h | 28 ++ src/sksl/ir/SkSLTernaryExpression.h | 4 + src/sksl/ir/SkSLTypeReference.h | 4 + src/sksl/ir/SkSLUnresolvedFunction.h | 2 +- src/sksl/ir/SkSLVarDeclarations.h | 10 +- src/sksl/ir/SkSLVariable.h | 4 + src/sksl/ir/SkSLVariableReference.h | 66 +++-- src/sksl/ir/SkSLWhileStatement.h | 2 +- src/sksl/lex.sksl.c | 490 ++++++++++++++++++---------------- src/sksl/sksl.flex | 2 + src/sksl/sksl_frag.include | 2 +- src/sksl/sksl_geom.include | 8 +- tests/SkSLGLSLTest.cpp | 273 +++++++++++++------ 46 files changed, 1543 insertions(+), 537 deletions(-) create mode 100644 src/sksl/ir/SkSLNop.h diff --git a/src/sksl/SkSLCFGGenerator.cpp b/src/sksl/SkSLCFGGenerator.cpp index e2c038075b..6438d59366 100644 --- a/src/sksl/SkSLCFGGenerator.cpp +++ b/src/sksl/SkSLCFGGenerator.cpp @@ -56,7 +56,7 @@ void CFG::dump() { 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() : ""); + iter->second ? (*iter->second)->description().c_str() : ""); separator = ", "; } printf("\nEntrances: "); @@ -68,9 +68,9 @@ void CFG::dump() { printf("\n"); for (size_t j = 0; j < fBlocks[i].fNodes.size(); j++) { BasicBlock::Node& n = fBlocks[i].fNodes[j]; - printf("Node %d: %s\n", (int) j, n.fKind == BasicBlock::Node::kExpression_Kind - ? (*n.fExpression)->description().c_str() - : n.fStatement->description().c_str()); + 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 = ""; @@ -82,6 +82,207 @@ void CFG::dump() { } } +bool BasicBlock::tryRemoveExpressionBefore(std::vector::iterator* iter, + Expression* e) { + if (e->fKind == Expression::kTernary_Kind) { + return false; + } + bool result; + if ((*iter)->fKind == BasicBlock::Node::kExpression_Kind) { + ASSERT((*iter)->expression()->get() != e); + Expression* old = (*iter)->expression()->get(); + do { + if ((*iter) == fNodes.begin()) { + ABORT("couldn't find %s before %s\n", e->description().c_str(), + old->description().c_str()); + } + --(*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) { + ASSERT(*iter != fNodes.end()); + ++(*iter); + } + } else { + Statement* old = (*iter)->statement()->get(); + do { + if ((*iter) == fNodes.begin()) { + ABORT("couldn't find %s before %s\n", e->description().c_str(), + old->description().c_str()); + } + --(*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) { + ASSERT(*iter != fNodes.end()); + ++(*iter); + } + } + return result; +} + +bool BasicBlock::tryRemoveLValueBefore(std::vector::iterator* iter, + Expression* lvalue) { + switch (lvalue->fKind) { + 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()); + default: + ABORT("invalid lvalue: %s\n", lvalue->description().c_str()); + } +} + +bool BasicBlock::tryRemoveExpression(std::vector::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; + } + ASSERT((*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; + } + ASSERT((*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; + } + ASSERT((*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::kVariableReference_Kind: + *iter = fNodes.erase(*iter); + return true; + default: + ABORT("unhandled expression: %s\n", expr->description().c_str()); + } +} + +bool BasicBlock::tryInsertExpression(std::vector::iterator* iter, + std::unique_ptr* 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* e, bool constantPropagate) { ASSERT(e); switch ((*e)->fKind) { @@ -182,6 +383,8 @@ void CFGGenerator::addExpression(CFG& cfg, std::unique_ptr* e, bool 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); @@ -223,24 +426,26 @@ void CFGGenerator::addLValue(CFG& cfg, std::unique_ptr* e) { } } -void CFGGenerator::addStatement(CFG& cfg, const Statement* s) { - switch (s->fKind) { +void CFGGenerator::addStatement(CFG& cfg, std::unique_ptr* s) { + switch ((*s)->fKind) { case Statement::kBlock_Kind: - for (const auto& child : ((const Block*) s)->fStatements) { - addStatement(cfg, child.get()); + for (auto& child : ((Block&) **s).fStatements) { + addStatement(cfg, &child); } break; case Statement::kIf_Kind: { - IfStatement* ifs = (IfStatement*) s; - this->addExpression(cfg, &ifs->fTest, true); + 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.get()); + this->addStatement(cfg, &ifs.fIfTrue); BlockId next = cfg.newBlock(); - if (ifs->fIfFalse) { + if (ifs.fIfFalse) { cfg.fCurrent = start; cfg.newBlock(); - this->addStatement(cfg, ifs->fIfFalse.get()); + this->addStatement(cfg, &ifs.fIfFalse); cfg.addExit(cfg.fCurrent, next); cfg.fCurrent = next; } else { @@ -249,14 +454,16 @@ void CFGGenerator::addStatement(CFG& cfg, const Statement* s) { break; } case Statement::kExpression_Kind: { - this->addExpression(cfg, &((ExpressionStatement&) *s).fExpression, true); + 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); + VarDeclarationsStatement& decls = ((VarDeclarationsStatement&) **s); for (auto& vd : decls.fDeclaration->fVars) { - if (vd.fValue) { - this->addExpression(cfg, &vd.fValue, true); + if (vd->fValue) { + this->addExpression(cfg, &vd->fValue, true); } } cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kStatement_Kind, false, @@ -269,7 +476,7 @@ void CFGGenerator::addStatement(CFG& cfg, const Statement* s) { cfg.fCurrent = cfg.newIsolatedBlock(); break; case Statement::kReturn_Kind: { - ReturnStatement& r = ((ReturnStatement&) *s); + ReturnStatement& r = ((ReturnStatement&) **s); if (r.fExpression) { this->addExpression(cfg, &r.fExpression, true); } @@ -291,16 +498,16 @@ void CFGGenerator::addStatement(CFG& cfg, const Statement* s) { cfg.fCurrent = cfg.newIsolatedBlock(); break; case Statement::kWhile_Kind: { - WhileStatement* w = (WhileStatement*) s; + WhileStatement& w = (WhileStatement&) **s; BlockId loopStart = cfg.newBlock(); fLoopContinues.push(loopStart); BlockId loopExit = cfg.newIsolatedBlock(); fLoopExits.push(loopExit); - this->addExpression(cfg, &w->fTest, true); + this->addExpression(cfg, &w.fTest, true); BlockId test = cfg.fCurrent; cfg.addExit(test, loopExit); cfg.newBlock(); - this->addStatement(cfg, w->fStatement.get()); + this->addStatement(cfg, &w.fStatement); cfg.addExit(cfg.fCurrent, loopStart); fLoopContinues.pop(); fLoopExits.pop(); @@ -308,13 +515,13 @@ void CFGGenerator::addStatement(CFG& cfg, const Statement* s) { break; } case Statement::kDo_Kind: { - DoStatement* d = (DoStatement*) s; + DoStatement& d = (DoStatement&) **s; BlockId loopStart = cfg.newBlock(); fLoopContinues.push(loopStart); BlockId loopExit = cfg.newIsolatedBlock(); fLoopExits.push(loopExit); - this->addStatement(cfg, d->fStatement.get()); - this->addExpression(cfg, &d->fTest, true); + this->addStatement(cfg, &d.fStatement); + this->addExpression(cfg, &d.fTest, true); cfg.addExit(cfg.fCurrent, loopExit); cfg.addExit(cfg.fCurrent, loopStart); fLoopContinues.pop(); @@ -323,26 +530,26 @@ void CFGGenerator::addStatement(CFG& cfg, const Statement* s) { break; } case Statement::kFor_Kind: { - ForStatement* f = (ForStatement*) s; - if (f->fInitializer) { - this->addStatement(cfg, f->fInitializer.get()); + 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); + if (f.fTest) { + this->addExpression(cfg, &f.fTest, true); BlockId test = cfg.fCurrent; cfg.addExit(test, loopExit); } cfg.newBlock(); - this->addStatement(cfg, f->fStatement.get()); + this->addStatement(cfg, &f.fStatement); cfg.addExit(cfg.fCurrent, next); cfg.fCurrent = next; - if (f->fNext) { - this->addExpression(cfg, &f->fNext, true); + if (f.fNext) { + this->addExpression(cfg, &f.fNext, true); } cfg.addExit(cfg.fCurrent, loopStart); fLoopContinues.pop(); @@ -351,12 +558,12 @@ void CFGGenerator::addStatement(CFG& cfg, const Statement* s) { break; } case Statement::kSwitch_Kind: { - SwitchStatement* ss = (SwitchStatement*) s; - this->addExpression(cfg, &ss->fValue, true); + SwitchStatement& ss = (SwitchStatement&) **s; + this->addExpression(cfg, &ss.fValue, true); BlockId start = cfg.fCurrent; BlockId switchExit = cfg.newIsolatedBlock(); fLoopExits.push(switchExit); - for (const auto& c : ss->fCases) { + for (const auto& c : ss.fCases) { cfg.newBlock(); cfg.addExit(start, cfg.fCurrent); if (c->fValue) { @@ -364,13 +571,13 @@ void CFGGenerator::addStatement(CFG& cfg, const Statement* s) { // because it must be constant. Not worth running two loops for. this->addExpression(cfg, &c->fValue, true); } - for (const auto& caseStatement : c->fStatements) { - this->addStatement(cfg, caseStatement.get()); + 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) { + 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); } @@ -378,17 +585,19 @@ void CFGGenerator::addStatement(CFG& cfg, const Statement* s) { cfg.fCurrent = switchExit; break; } + case Statement::kNop_Kind: + break; default: - printf("statement: %s\n", s->description().c_str()); + printf("statement: %s\n", (*s)->description().c_str()); ABORT("unsupported statement kind"); } } -CFG CFGGenerator::getCFG(const FunctionDefinition& f) { +CFG CFGGenerator::getCFG(FunctionDefinition& f) { CFG result; result.fStart = result.newBlock(); result.fCurrent = result.fStart; - this->addStatement(result, f.fBody.get()); + this->addStatement(result, &f.fBody); result.newBlock(); result.fExit = result.fCurrent; return result; diff --git a/src/sksl/SkSLCFGGenerator.h b/src/sksl/SkSLCFGGenerator.h index 0a03d69fc6..885d9261ec 100644 --- a/src/sksl/SkSLCFGGenerator.h +++ b/src/sksl/SkSLCFGGenerator.h @@ -26,6 +26,42 @@ struct BasicBlock { kExpression_Kind }; + Node(Kind kind, bool constantPropagation, std::unique_ptr* expression, + std::unique_ptr* statement) + : fKind(kind) + , fConstantPropagation(constantPropagation) + , fExpression(expression) + , fStatement(statement) {} + + std::unique_ptr* expression() const { + ASSERT(fKind == kExpression_Kind); + return fExpression; + } + + void setExpression(std::unique_ptr expr) { + ASSERT(fKind == kExpression_Kind); + *fExpression = std::move(expr); + } + + std::unique_ptr* statement() const { + ASSERT(fKind == kStatement_Kind); + return fStatement; + } + + void setStatement(std::unique_ptr stmt) { + ASSERT(fKind == kStatement_Kind); + *fStatement = std::move(stmt); + } + + String description() const { + if (fKind == kStatement_Kind) { + return (*fStatement)->description(); + } else { + ASSERT(fKind == kExpression_Kind); + return (*fExpression)->description(); + } + } + Kind fKind; // if false, this node should not be subject to constant propagation. This happens with // compound assignment (i.e. x *= 2), in which the value x is used as an rvalue for @@ -35,10 +71,45 @@ struct BasicBlock { // assignment if the target is constant (i.e. x = 1; x *= 2; should become x = 1; x = 1 * 2; // and then collapse down to a simple x = 2;). bool fConstantPropagation; + + private: + // we store pointers to the unique_ptrs so that we can replace expressions or statements + // during optimization without having to regenerate the entire tree std::unique_ptr* fExpression; - const Statement* fStatement; + std::unique_ptr* fStatement; }; + /** + * Attempts to remove the expression (and its subexpressions) pointed to by the iterator. If the + * expression can be cleanly removed, returns true and updates the iterator to point to the + * expression after the deleted expression. Otherwise returns false (and the CFG will need to be + * regenerated). + */ + bool tryRemoveExpression(std::vector::iterator* iter); + + /** + * Locates and attempts remove an expression occurring before the expression pointed to by iter. + * If the expression can be cleanly removed, returns true and resets iter to a valid iterator + * pointing to the same expression it did initially. Otherwise returns false (and the CFG will + * need to be regenerated). + */ + bool tryRemoveExpressionBefore(std::vector::iterator* iter, Expression* e); + + /** + * As tryRemoveExpressionBefore, but for lvalues. As lvalues are at most partially evaluated + * (for instance, x[i] = 0 evaluates i but not x) this will only look for the parts of the + * lvalue that are actually evaluated. + */ + bool tryRemoveLValueBefore(std::vector::iterator* iter, Expression* lvalue); + + /** + * Attempts to inserts a new expression before the node pointed to by iter. If the + * expression can be cleanly inserted, returns true and updates the iterator to point to the + * newly inserted expression. Otherwise returns false (and the CFG will need to be regenerated). + */ + bool tryInsertExpression(std::vector::iterator* iter, + std::unique_ptr* expr); + std::vector fNodes; std::set fEntrances; std::set fExits; @@ -81,10 +152,10 @@ class CFGGenerator { public: CFGGenerator() {} - CFG getCFG(const FunctionDefinition& f); + CFG getCFG(FunctionDefinition& f); private: - void addStatement(CFG& cfg, const Statement* s); + void addStatement(CFG& cfg, std::unique_ptr* s); void addExpression(CFG& cfg, std::unique_ptr* e, bool constantPropagate); diff --git a/src/sksl/SkSLCompiler.cpp b/src/sksl/SkSLCompiler.cpp index ea87e99938..e4ab700591 100644 --- a/src/sksl/SkSLCompiler.cpp +++ b/src/sksl/SkSLCompiler.cpp @@ -14,9 +14,12 @@ #include "SkSLParser.h" #include "SkSLSPIRVCodeGenerator.h" #include "ir/SkSLExpression.h" +#include "ir/SkSLExpressionStatement.h" #include "ir/SkSLIntLiteral.h" #include "ir/SkSLModifiersDeclaration.h" +#include "ir/SkSLNop.h" #include "ir/SkSLSymbolTable.h" +#include "ir/SkSLTernaryExpression.h" #include "ir/SkSLUnresolvedFunction.h" #include "ir/SkSLVarDeclarations.h" @@ -207,8 +210,8 @@ void Compiler::addDefinitions(const BasicBlock::Node& node, DefinitionMap* definitions) { switch (node.fKind) { case BasicBlock::Node::kExpression_Kind: { - ASSERT(node.fExpression); - const Expression* expr = (Expression*) node.fExpression->get(); + ASSERT(node.expression()); + const Expression* expr = (Expression*) node.expression()->get(); switch (expr->fKind) { case Expression::kBinary_Kind: { BinaryExpression* b = (BinaryExpression*) expr; @@ -240,22 +243,30 @@ void Compiler::addDefinitions(const BasicBlock::Node& node, p->fOperand.get(), (std::unique_ptr*) &fContext.fDefined_Expression, definitions); - } break; } + case Expression::kVariableReference_Kind: { + const VariableReference* v = (VariableReference*) expr; + if (v->fRefKind != VariableReference::kRead_RefKind) { + this->addDefinition( + v, + (std::unique_ptr*) &fContext.fDefined_Expression, + definitions); + } + } default: break; } break; } case BasicBlock::Node::kStatement_Kind: { - const Statement* stmt = (Statement*) node.fStatement; + const Statement* stmt = (Statement*) node.statement()->get(); if (stmt->fKind == Statement::kVarDeclarations_Kind) { VarDeclarationsStatement* vd = (VarDeclarationsStatement*) stmt; - for (VarDeclaration& decl : vd->fDeclaration->fVars) { - if (decl.fValue) { - (*definitions)[decl.fVar] = &decl.fValue; + for (const auto& decl : vd->fDeclaration->fVars) { + if (decl->fValue) { + (*definitions)[decl->fVar] = &decl->fValue; } } } @@ -308,12 +319,12 @@ static DefinitionMap compute_start_state(const CFG& cfg) { for (const auto& block : cfg.fBlocks) { for (const auto& node : block.fNodes) { if (node.fKind == BasicBlock::Node::kStatement_Kind) { - ASSERT(node.fStatement); - const Statement* s = node.fStatement; + ASSERT(node.statement()); + const Statement* s = node.statement()->get(); if (s->fKind == Statement::kVarDeclarations_Kind) { const VarDeclarationsStatement* vd = (const VarDeclarationsStatement*) s; - for (const VarDeclaration& decl : vd->fDeclaration->fVars) { - result[decl.fVar] = nullptr; + for (const auto& decl : vd->fDeclaration->fVars) { + result[decl->fVar] = nullptr; } } } @@ -322,20 +333,290 @@ static DefinitionMap compute_start_state(const CFG& cfg) { return result; } -void Compiler::scanCFG(const FunctionDefinition& f) { - CFG cfg = CFGGenerator().getCFG(f); +/** + * Returns true if assigning to this lvalue has no effect. + */ +static bool is_dead(const Expression& lvalue) { + switch (lvalue.fKind) { + case Expression::kVariableReference_Kind: + return ((VariableReference&) lvalue).fVariable.dead(); + case Expression::kSwizzle_Kind: + return is_dead(*((Swizzle&) lvalue).fBase); + case Expression::kFieldAccess_Kind: + return is_dead(*((FieldAccess&) lvalue).fBase); + case Expression::kIndex_Kind: { + const IndexExpression& idx = (IndexExpression&) lvalue; + return is_dead(*idx.fBase) && !idx.fIndex->hasSideEffects(); + } + default: + ABORT("invalid lvalue: %s\n", lvalue.description().c_str()); + } +} + +/** + * Returns true if this is an assignment which can be collapsed down to just the right hand side due + * to a dead target and lack of side effects on the left hand side. + */ +static bool dead_assignment(const BinaryExpression& b) { + if (!Token::IsAssignment(b.fOperator)) { + return false; + } + return is_dead(*b.fLeft); +} - // compute the data flow - cfg.fBlocks[cfg.fStart].fBefore = compute_start_state(cfg); +void Compiler::computeDataFlow(CFG* cfg) { + cfg->fBlocks[cfg->fStart].fBefore = compute_start_state(*cfg); std::set workList; - for (BlockId i = 0; i < cfg.fBlocks.size(); i++) { + for (BlockId i = 0; i < cfg->fBlocks.size(); i++) { workList.insert(i); } while (workList.size()) { BlockId next = *workList.begin(); workList.erase(workList.begin()); - this->scanCFG(&cfg, next, &workList); + this->scanCFG(cfg, next, &workList); + } +} + +/** + * Attempts to replace the expression pointed to by iter with a new one (in both the CFG and the + * IR). If the expression can be cleanly removed, returns true and updates the iterator to point to + * the newly-inserted element. Otherwise updates only the IR and returns false (and the CFG will + * need to be regenerated). + */ +bool try_replace_expression(BasicBlock* b, + std::vector::iterator* iter, + std::unique_ptr* newExpression) { + std::unique_ptr* target = (*iter)->expression(); + if (!b->tryRemoveExpression(iter)) { + *target = std::move(*newExpression); + return false; + } + *target = std::move(*newExpression); + return b->tryInsertExpression(iter, target); +} + +/** + * Returns true if the expression is a constant numeric literal with the specified value. + */ +bool is_constant(Expression& expr, double value) { + switch (expr.fKind) { + case Expression::kIntLiteral_Kind: + return ((IntLiteral&) expr).fValue == value; + case Expression::kFloatLiteral_Kind: + return ((FloatLiteral&) expr).fValue == value; + default: + return false; + } +} + +/** + * Collapses the binary expression pointed to by iter down to just the right side (in both the IR + * and CFG structures). + */ +void delete_left(BasicBlock* b, + std::vector::iterator* iter, + bool* outUpdated, + bool* outNeedsRescan) { + *outUpdated = true; + if (!try_replace_expression(b, iter, &((BinaryExpression&) **(*iter)->expression()).fRight)) { + *outNeedsRescan = true; + } +} + +/** + * Collapses the binary expression pointed to by iter down to just the left side (in both the IR and + * CFG structures). + */ +void delete_right(BasicBlock* b, + std::vector::iterator* iter, + bool* outUpdated, + bool* outNeedsRescan) { + *outUpdated = true; + if (!try_replace_expression(b, iter, &((BinaryExpression&) **(*iter)->expression()).fLeft)) { + *outNeedsRescan = true; + } +} + +void Compiler::simplifyExpression(DefinitionMap& definitions, + BasicBlock& b, + std::vector::iterator* iter, + std::unordered_set* undefinedVariables, + bool* outUpdated, + bool* outNeedsRescan) { + Expression* expr = (*iter)->expression()->get(); + ASSERT(expr); + if ((*iter)->fConstantPropagation) { + std::unique_ptr optimized = expr->constantPropagate(*fIRGenerator, definitions); + if (optimized) { + if (!try_replace_expression(&b, iter, &optimized)) { + *outNeedsRescan = true; + } + ASSERT((*iter)->fKind == BasicBlock::Node::kExpression_Kind); + expr = (*iter)->expression()->get(); + *outUpdated = true; + } + } + switch (expr->fKind) { + case Expression::kVariableReference_Kind: { + const Variable& var = ((VariableReference*) expr)->fVariable; + if (var.fStorage == Variable::kLocal_Storage && !definitions[&var] && + (*undefinedVariables).find(&var) == (*undefinedVariables).end()) { + (*undefinedVariables).insert(&var); + this->error(expr->fPosition, + "'" + var.fName + "' has not been assigned"); + } + break; + } + case Expression::kTernary_Kind: { + TernaryExpression* t = (TernaryExpression*) expr; + if (t->fTest->fKind == Expression::kBoolLiteral_Kind) { + // ternary has a constant test, replace it with either the true or + // false branch + if (((BoolLiteral&) *t->fTest).fValue) { + (*iter)->setExpression(std::move(t->fIfTrue)); + } else { + (*iter)->setExpression(std::move(t->fIfFalse)); + } + *outUpdated = true; + *outNeedsRescan = true; + } + break; + } + case Expression::kBinary_Kind: { + // collapse useless expressions like x * 1 or x + 0 + BinaryExpression* bin = (BinaryExpression*) expr; + switch (bin->fOperator) { + case Token::STAR: + if (is_constant(*bin->fLeft, 1)) { + delete_left(&b, iter, outUpdated, outNeedsRescan); + } + else if (is_constant(*bin->fRight, 1)) { + delete_right(&b, iter, outUpdated, outNeedsRescan); + } + break; + case Token::PLUS: // fall through + case Token::MINUS: + if (is_constant(*bin->fLeft, 0)) { + delete_left(&b, iter, outUpdated, outNeedsRescan); + } + else if (is_constant(*bin->fRight, 0)) { + delete_right(&b, iter, outUpdated, outNeedsRescan); + } + break; + case Token::SLASH: + if (is_constant(*bin->fRight, 1)) { + delete_right(&b, iter, outUpdated, outNeedsRescan); + } + break; + default: + break; + } + } + default: + break; } +} + +void Compiler::simplifyStatement(DefinitionMap& definitions, + BasicBlock& b, + std::vector::iterator* iter, + std::unordered_set* undefinedVariables, + bool* outUpdated, + bool* outNeedsRescan) { + Statement* stmt = (*iter)->statement()->get(); + switch (stmt->fKind) { + case Statement::kVarDeclarations_Kind: { + VarDeclarations& vd = *((VarDeclarationsStatement&) *stmt).fDeclaration; + for (auto varIter = vd.fVars.begin(); varIter != vd.fVars.end(); ) { + const auto& varDecl = **varIter; + if (varDecl.fVar->dead() && + (!varDecl.fValue || + !varDecl.fValue->hasSideEffects())) { + if (varDecl.fValue) { + ASSERT((*iter)->statement()->get() == stmt); + if (!b.tryRemoveExpressionBefore(iter, varDecl.fValue.get())) { + *outNeedsRescan = true; + } + } + varIter = vd.fVars.erase(varIter); + *outUpdated = true; + } else { + ++varIter; + } + } + if (vd.fVars.size() == 0) { + (*iter)->setStatement(std::unique_ptr(new Nop())); + } + break; + } + case Statement::kIf_Kind: { + IfStatement& i = (IfStatement&) *stmt; + if (i.fIfFalse && i.fIfFalse->isEmpty()) { + // else block doesn't do anything, remove it + i.fIfFalse.reset(); + *outUpdated = true; + *outNeedsRescan = true; + } + if (!i.fIfFalse && i.fIfTrue->isEmpty()) { + // if block doesn't do anything, no else block + if (i.fTest->hasSideEffects()) { + // test has side effects, keep it + (*iter)->setStatement(std::unique_ptr( + new ExpressionStatement(std::move(i.fTest)))); + } else { + // no if, no else, no test side effects, kill the whole if + // statement + (*iter)->setStatement(std::unique_ptr(new Nop())); + } + *outUpdated = true; + *outNeedsRescan = true; + } + break; + } + case Statement::kExpression_Kind: { + ExpressionStatement& e = (ExpressionStatement&) *stmt; + ASSERT((*iter)->statement()->get() == &e); + if (e.fExpression->fKind == Expression::kBinary_Kind) { + BinaryExpression& bin = (BinaryExpression&) *e.fExpression; + if (dead_assignment(bin)) { + if (!b.tryRemoveExpressionBefore(iter, &bin)) { + *outNeedsRescan = true; + } + if (bin.fRight->hasSideEffects()) { + // still have to evaluate the right due to side effects, + // replace the binary expression with just the right side + e.fExpression = std::move(bin.fRight); + if (!b.tryInsertExpression(iter, &e.fExpression)) { + *outNeedsRescan = true; + } + } else { + // no side effects, kill the whole statement + ASSERT((*iter)->statement()->get() == stmt); + (*iter)->setStatement(std::unique_ptr(new Nop())); + } + *outUpdated = true; + break; + } + } + if (!e.fExpression->hasSideEffects()) { + // Expression statement with no side effects, kill it + if (!b.tryRemoveExpressionBefore(iter, e.fExpression.get())) { + *outNeedsRescan = true; + } + ASSERT((*iter)->statement()->get() == stmt); + (*iter)->setStatement(std::unique_ptr(new Nop())); + *outUpdated = true; + } + break; + } + default: + break; + } +} + +void Compiler::scanCFG(FunctionDefinition& f) { + CFG cfg = CFGGenerator().getCFG(f); + this->computeDataFlow(&cfg); // check for unreachable code for (size_t i = 0; i < cfg.fBlocks.size(); i++) { @@ -344,10 +625,10 @@ void Compiler::scanCFG(const FunctionDefinition& f) { Position p; switch (cfg.fBlocks[i].fNodes[0].fKind) { case BasicBlock::Node::kStatement_Kind: - p = cfg.fBlocks[i].fNodes[0].fStatement->fPosition; + p = (*cfg.fBlocks[i].fNodes[0].statement())->fPosition; break; case BasicBlock::Node::kExpression_Kind: - p = (*cfg.fBlocks[i].fNodes[0].fExpression)->fPosition; + p = (*cfg.fBlocks[i].fNodes[0].expression())->fPosition; break; } this->error(p, String("unreachable")); @@ -357,33 +638,34 @@ void Compiler::scanCFG(const FunctionDefinition& f) { return; } - // check for undefined variables, perform constant propagation - for (BasicBlock& b : cfg.fBlocks) { - DefinitionMap definitions = b.fBefore; - for (BasicBlock::Node& n : b.fNodes) { - if (n.fKind == BasicBlock::Node::kExpression_Kind) { - ASSERT(n.fExpression); - Expression* expr = n.fExpression->get(); - if (n.fConstantPropagation) { - std::unique_ptr optimized = expr->constantPropagate(*fIRGenerator, - definitions); - if (optimized) { - n.fExpression->reset(optimized.release()); - expr = n.fExpression->get(); - } - } - if (expr->fKind == Expression::kVariableReference_Kind) { - const Variable& var = ((VariableReference*) expr)->fVariable; - if (var.fStorage == Variable::kLocal_Storage && - !definitions[&var]) { - this->error(expr->fPosition, - "'" + var.fName + "' has not been assigned"); - } + // check for dead code & undefined variables, perform constant propagation + std::unordered_set undefinedVariables; + bool updated; + bool needsRescan = false; + do { + if (needsRescan) { + cfg = CFGGenerator().getCFG(f); + this->computeDataFlow(&cfg); + needsRescan = false; + } + + updated = false; + for (BasicBlock& b : cfg.fBlocks) { + DefinitionMap definitions = b.fBefore; + + for (auto iter = b.fNodes.begin(); iter != b.fNodes.end() && !needsRescan; ++iter) { + if (iter->fKind == BasicBlock::Node::kExpression_Kind) { + this->simplifyExpression(definitions, b, &iter, &undefinedVariables, &updated, + &needsRescan); + } else { + this->simplifyStatement(definitions, b, &iter, &undefinedVariables, &updated, + &needsRescan); } + this->addDefinitions(*iter, &definitions); } - this->addDefinitions(n, &definitions); } - } + } while (updated); + ASSERT(!needsRescan); // check for missing return if (f.fDeclaration.fReturnType != *fContext.fVoid_Type) { diff --git a/src/sksl/SkSLCompiler.h b/src/sksl/SkSLCompiler.h index 7e3c83edff..5e7bc9e71b 100644 --- a/src/sksl/SkSLCompiler.h +++ b/src/sksl/SkSLCompiler.h @@ -9,6 +9,7 @@ #define SKSL_COMPILER #include +#include #include #include "ir/SkSLProgram.h" #include "ir/SkSLSymbolTable.h" @@ -71,7 +72,31 @@ private: void scanCFG(CFG* cfg, BlockId block, std::set* workList); - void scanCFG(const FunctionDefinition& f); + void computeDataFlow(CFG* cfg); + + /** + * Simplifies the expression pointed to by iter (in both the IR and CFG structures), if + * possible. + */ + void simplifyExpression(DefinitionMap& definitions, + BasicBlock& b, + std::vector::iterator* iter, + std::unordered_set* undefinedVariables, + bool* outUpdated, + bool* outNeedsRescan); + + /** + * Simplifies the statement pointed to by iter (in both the IR and CFG structures), if + * possible. + */ + void simplifyStatement(DefinitionMap& definitions, + BasicBlock& b, + std::vector::iterator* iter, + std::unordered_set* undefinedVariables, + bool* outUpdated, + bool* outNeedsRescan); + + void scanCFG(FunctionDefinition& f); void internalConvertProgram(String text, Modifiers::Flag* defaultPrecision, diff --git a/src/sksl/SkSLContext.h b/src/sksl/SkSLContext.h index 450baa5d77..a9ebe9db06 100644 --- a/src/sksl/SkSLContext.h +++ b/src/sksl/SkSLContext.h @@ -283,6 +283,10 @@ private: virtual String description() const override { return String(""); } + + bool hasSideEffects() const override { + return false; + } typedef Expression INHERITED; }; diff --git a/src/sksl/SkSLGLSLCodeGenerator.cpp b/src/sksl/SkSLGLSLCodeGenerator.cpp index ab64e66f7c..8099d45475 100644 --- a/src/sksl/SkSLGLSLCodeGenerator.cpp +++ b/src/sksl/SkSLGLSLCodeGenerator.cpp @@ -14,6 +14,7 @@ #include "ir/SkSLExtension.h" #include "ir/SkSLIndexExpression.h" #include "ir/SkSLModifiersDeclaration.h" +#include "ir/SkSLNop.h" #include "ir/SkSLVariableReference.h" namespace SkSL { @@ -509,10 +510,7 @@ void GLSLCodeGenerator::writeFunction(const FunctionDefinition& f) { StringStream buffer; fOut = &buffer; fIndentation++; - for (const auto& s : f.fBody->fStatements) { - this->writeStatement(*s); - this->writeLine(); - } + this->writeStatements(((Block&) *f.fBody).fStatements); fIndentation--; this->writeLine("}"); @@ -620,26 +618,26 @@ void GLSLCodeGenerator::writeInterfaceBlock(const InterfaceBlock& intf) { void GLSLCodeGenerator::writeVarDeclarations(const VarDeclarations& decl, bool global) { ASSERT(decl.fVars.size() > 0); - this->writeModifiers(decl.fVars[0].fVar->fModifiers, global); + this->writeModifiers(decl.fVars[0]->fVar->fModifiers, global); this->writeType(decl.fBaseType); String separator(" "); for (const auto& var : decl.fVars) { - ASSERT(var.fVar->fModifiers == decl.fVars[0].fVar->fModifiers); + ASSERT(var->fVar->fModifiers == decl.fVars[0]->fVar->fModifiers); this->write(separator); separator = String(", "); - this->write(var.fVar->fName); - for (const auto& size : var.fSizes) { + this->write(var->fVar->fName); + for (const auto& size : var->fSizes) { this->write("["); if (size) { this->writeExpression(*size, kTopLevel_Precedence); } this->write("]"); } - if (var.fValue) { + if (var->fValue) { this->write(" = "); - this->writeExpression(*var.fValue, kTopLevel_Precedence); + this->writeExpression(*var->fValue, kTopLevel_Precedence); } - if (!fFoundImageDecl && var.fVar->fType == *fContext.fImage2D_Type) { + if (!fFoundImageDecl && var->fVar->fType == *fContext.fImage2D_Type) { if (fProgram.fSettings.fCaps->imageLoadStoreExtensionString()) { fHeader.writeText("#extension "); fHeader.writeText(fProgram.fSettings.fCaps->imageLoadStoreExtensionString()); @@ -690,18 +688,27 @@ void GLSLCodeGenerator::writeStatement(const Statement& s) { case Statement::kDiscard_Kind: this->write("discard;"); break; + case Statement::kNop_Kind: + this->write(";"); + break; default: ABORT("unsupported statement: %s", s.description().c_str()); } } +void GLSLCodeGenerator::writeStatements(const std::vector>& statements) { + for (const auto& s : statements) { + if (!s->isEmpty()) { + this->writeStatement(*s); + this->writeLine(); + } + } +} + void GLSLCodeGenerator::writeBlock(const Block& b) { this->writeLine("{"); fIndentation++; - for (const auto& s : b.fStatements) { - this->writeStatement(*s); - this->writeLine(); - } + this->writeStatements(b.fStatements); fIndentation--; this->write("}"); } @@ -821,7 +828,7 @@ bool GLSLCodeGenerator::generateCode() { case ProgramElement::kVar_Kind: { VarDeclarations& decl = (VarDeclarations&) *e; if (decl.fVars.size() > 0) { - int builtin = decl.fVars[0].fVar->fModifiers.fLayout.fBuiltin; + int builtin = decl.fVars[0]->fVar->fModifiers.fLayout.fBuiltin; if (builtin == -1) { // normal var this->writeVarDeclarations(decl, true); diff --git a/src/sksl/SkSLGLSLCodeGenerator.h b/src/sksl/SkSLGLSLCodeGenerator.h index ab88d50881..65be7dc09e 100644 --- a/src/sksl/SkSLGLSLCodeGenerator.h +++ b/src/sksl/SkSLGLSLCodeGenerator.h @@ -145,6 +145,8 @@ private: void writeStatement(const Statement& s); + void writeStatements(const std::vector>& statements); + void writeBlock(const Block& b); void writeIfStatement(const IfStatement& stmt); diff --git a/src/sksl/SkSLIRGenerator.cpp b/src/sksl/SkSLIRGenerator.cpp index 975b05f1c9..56858a92ca 100644 --- a/src/sksl/SkSLIRGenerator.cpp +++ b/src/sksl/SkSLIRGenerator.cpp @@ -210,7 +210,7 @@ std::unique_ptr IRGenerator::convertVarDeclarationStatement( std::unique_ptr IRGenerator::convertVarDeclarations(const ASTVarDeclarations& decl, Variable::Storage storage) { - std::vector variables; + std::vector> variables; const Type* baseType = this->convertType(*decl.fType); if (!baseType) { return nullptr; @@ -254,6 +254,7 @@ std::unique_ptr IRGenerator::convertVarDeclarations(const ASTVa return nullptr; } value = this->coerce(std::move(value), *type); + var->fWriteCount = 1; } if (storage == Variable::kGlobal_Storage && varDecl.fName == String("sk_FragColor") && (*fSymbolTable)[varDecl.fName]) { @@ -265,7 +266,8 @@ std::unique_ptr IRGenerator::convertVarDeclarations(const ASTVa Variable* old = (Variable*) (*fSymbolTable)[varDecl.fName]; old->fModifiers = var->fModifiers; } else { - variables.emplace_back(var.get(), std::move(sizes), std::move(value)); + variables.emplace_back(new VarDeclaration(var.get(), std::move(sizes), + std::move(value))); fSymbolTable->add(varDecl.fName, std::move(var)); } } @@ -542,7 +544,8 @@ std::unique_ptr IRGenerator::convertFunction(const ASTFuncti } if (match) { if (*returnType != other->fReturnType) { - FunctionDeclaration newDecl(f.fPosition, f.fName, parameters, *returnType); + FunctionDeclaration newDecl(f.fPosition, f.fModifiers, f.fName, parameters, + *returnType); fErrors.error(f.fPosition, "functions '" + newDecl.description() + "' and '" + other->description() + "' differ only in return type"); @@ -570,6 +573,7 @@ std::unique_ptr IRGenerator::convertFunction(const ASTFuncti if (!decl) { // couldn't find an existing declaration auto newDecl = std::unique_ptr(new FunctionDeclaration(f.fPosition, + f.fModifiers, f.fName, parameters, *returnType)); @@ -590,6 +594,8 @@ std::unique_ptr IRGenerator::convertFunction(const ASTFuncti if (!body) { return nullptr; } + // conservatively assume all user-defined functions have side effects + ((Modifiers&) decl->fModifiers).fFlags |= Modifiers::kHasSideEffects_Flag; return std::unique_ptr(new FunctionDefinition(f.fPosition, *decl, std::move(body))); } @@ -608,16 +614,16 @@ std::unique_ptr IRGenerator::convertInterfaceBlock(const ASTInte return nullptr; } for (const auto& var : decl->fVars) { - fields.push_back(Type::Field(var.fVar->fModifiers, var.fVar->fName, - &var.fVar->fType)); - if (var.fValue) { + fields.push_back(Type::Field(var->fVar->fModifiers, var->fVar->fName, + &var->fVar->fType)); + if (var->fValue) { fErrors.error(decl->fPosition, "initializers are not permitted on interface block fields"); } - if (var.fVar->fModifiers.fFlags & (Modifiers::kIn_Flag | - Modifiers::kOut_Flag | - Modifiers::kUniform_Flag | - Modifiers::kConst_Flag)) { + if (var->fVar->fModifiers.fFlags & (Modifiers::kIn_Flag | + Modifiers::kOut_Flag | + Modifiers::kUniform_Flag | + Modifiers::kConst_Flag)) { fErrors.error(decl->fPosition, "interface block fields may not have storage qualifiers"); } @@ -944,6 +950,9 @@ static bool determine_binary_type(const Context& context, std::unique_ptr IRGenerator::constantFold(const Expression& left, Token::Kind op, const Expression& right) const { + if (!left.isConstant() || !right.isConstant()) { + return nullptr; + } // Note that we expressly do not worry about precision and overflow here -- we use the maximum // precision to calculate the results and hope the result makes sense. The plan is to move the // Skia caps into SkSL, so we have access to all of them including the precisions of the various @@ -967,9 +976,9 @@ std::unique_ptr IRGenerator::constantFold(const Expression& left, int64_t leftVal = ((IntLiteral&) left).fValue; int64_t rightVal = ((IntLiteral&) right).fValue; switch (op) { - case Token::PLUS: return RESULT(Int, +); - case Token::MINUS: return RESULT(Int, -); - case Token::STAR: return RESULT(Int, *); + case Token::PLUS: return RESULT(Int, +); + case Token::MINUS: return RESULT(Int, -); + case Token::STAR: return RESULT(Int, *); case Token::SLASH: if (rightVal) { return RESULT(Int, /); @@ -1010,15 +1019,37 @@ std::unique_ptr IRGenerator::constantFold(const Expression& left, } fErrors.error(right.fPosition, "division by zero"); return nullptr; - case Token::EQEQ: return RESULT(Bool, ==); - case Token::NEQ: return RESULT(Bool, !=); - case Token::GT: return RESULT(Bool, >); - case Token::GTEQ: return RESULT(Bool, >=); - case Token::LT: return RESULT(Bool, <); - case Token::LTEQ: return RESULT(Bool, <=); + case Token::EQEQ: return RESULT(Bool, ==); + case Token::NEQ: return RESULT(Bool, !=); + case Token::GT: return RESULT(Bool, >); + case Token::GTEQ: return RESULT(Bool, >=); + case Token::LT: return RESULT(Bool, <); + case Token::LTEQ: return RESULT(Bool, <=); default: return nullptr; } } + if (left.fType.kind() == Type::kVector_Kind && + left.fType.componentType() == *fContext.fFloat_Type && + left.fType == right.fType) { + ASSERT(left.fKind == Expression::kConstructor_Kind); + ASSERT(right.fKind == Expression::kConstructor_Kind); + std::vector> args; + #define RETURN_VEC_COMPONENTWISE_RESULT(op) \ + for (int i = 0; i < left.fType.columns(); i++) { \ + float value = ((Constructor&) left).getFVecComponent(i) op \ + ((Constructor&) right).getFVecComponent(i); \ + args.emplace_back(new FloatLiteral(fContext, Position(), value)); \ + } \ + return std::unique_ptr(new Constructor(Position(), left.fType, \ + std::move(args))); + switch (op) { + case Token::PLUS: RETURN_VEC_COMPONENTWISE_RESULT(+); + case Token::MINUS: RETURN_VEC_COMPONENTWISE_RESULT(-); + case Token::STAR: RETURN_VEC_COMPONENTWISE_RESULT(*); + case Token::SLASH: RETURN_VEC_COMPONENTWISE_RESULT(/); + default: return nullptr; + } + } #undef RESULT return nullptr; } @@ -1177,7 +1208,8 @@ std::unique_ptr IRGenerator::call(Position position, return nullptr; } if (arguments[i] && (function.fParameters[i]->fModifiers.fFlags & Modifiers::kOut_Flag)) { - this->markWrittenTo(*arguments[i], true); + this->markWrittenTo(*arguments[i], + function.fParameters[i]->fModifiers.fFlags & Modifiers::kIn_Flag); } } if (function.fBuiltin && function.fName == "texture" && diff --git a/src/sksl/SkSLParser.cpp b/src/sksl/SkSLParser.cpp index 0f2b943a9d..ae9d990d86 100644 --- a/src/sksl/SkSLParser.cpp +++ b/src/sksl/SkSLParser.cpp @@ -309,7 +309,7 @@ std::unique_ptr Parser::declaration() { if (!this->expect(Token::IDENTIFIER, "an identifier", &name)) { return nullptr; } - if (!modifiers.fFlags && this->peek().fKind == Token::LPAREN) { + if (this->peek().fKind == Token::LPAREN) { this->nextToken(); std::vector> parameters; while (this->peek().fKind != Token::RPAREN) { @@ -334,7 +334,9 @@ std::unique_ptr Parser::declaration() { return nullptr; } } - return std::unique_ptr(new ASTFunction(name.fPosition, std::move(type), + return std::unique_ptr(new ASTFunction(name.fPosition, + modifiers, + std::move(type), std::move(name.fText), std::move(parameters), std::move(body))); @@ -721,6 +723,10 @@ Modifiers Parser::modifiers() { this->nextToken(); flags |= Modifiers::kRestrict_Flag; break; + case Token::HASSIDEEFFECTS: + this->nextToken(); + flags |= Modifiers::kHasSideEffects_Flag; + break; default: return Modifiers(layout, flags); } diff --git a/src/sksl/SkSLSPIRVCodeGenerator.cpp b/src/sksl/SkSLSPIRVCodeGenerator.cpp index d713d6fddd..d2850e9131 100644 --- a/src/sksl/SkSLSPIRVCodeGenerator.cpp +++ b/src/sksl/SkSLSPIRVCodeGenerator.cpp @@ -2461,7 +2461,7 @@ SpvId SPIRVCodeGenerator::writeFunction(const FunctionDefinition& f, OutputStrea write_stringstream(fGlobalInitializersBuffer, out); } StringStream bodyBuffer; - this->writeBlock(*f.fBody, bodyBuffer); + this->writeBlock((Block&) *f.fBody, bodyBuffer); write_stringstream(fVariableBuffer, out); write_stringstream(bodyBuffer, out); if (fCurrentBlock) { @@ -2558,7 +2558,7 @@ SpvId SPIRVCodeGenerator::writeInterfaceBlock(const InterfaceBlock& intf) { void SPIRVCodeGenerator::writeGlobalVars(Program::Kind kind, const VarDeclarations& decl, OutputStream& out) { for (size_t i = 0; i < decl.fVars.size(); i++) { - const VarDeclaration& varDecl = decl.fVars[i]; + const VarDeclaration& varDecl = *decl.fVars[i]; const Variable* var = varDecl.fVar; // These haven't been implemented in our SPIR-V generator yet and we only currently use them // in the OpenGL backend. @@ -2620,7 +2620,7 @@ void SPIRVCodeGenerator::writeGlobalVars(Program::Kind kind, const VarDeclaratio void SPIRVCodeGenerator::writeVarDeclarations(const VarDeclarations& decl, OutputStream& out) { for (const auto& varDecl : decl.fVars) { - const Variable* var = varDecl.fVar; + const Variable* var = varDecl->fVar; // These haven't been implemented in our SPIR-V generator yet and we only currently use them // in the OpenGL backend. ASSERT(!(var->fModifiers.fFlags & (Modifiers::kReadOnly_Flag | @@ -2633,8 +2633,8 @@ void SPIRVCodeGenerator::writeVarDeclarations(const VarDeclarations& decl, Outpu SpvId type = this->getPointerType(var->fType, SpvStorageClassFunction); this->writeInstruction(SpvOpVariable, type, id, SpvStorageClassFunction, fVariableBuffer); this->writeInstruction(SpvOpName, id, var->fName.c_str(), fNameBuffer); - if (varDecl.fValue) { - SpvId value = this->writeExpression(*varDecl.fValue, out); + if (varDecl->fValue) { + SpvId value = this->writeExpression(*varDecl->fValue, out); this->writeInstruction(SpvOpStore, id, value, out); } } @@ -2642,6 +2642,8 @@ void SPIRVCodeGenerator::writeVarDeclarations(const VarDeclarations& decl, Outpu void SPIRVCodeGenerator::writeStatement(const Statement& s, OutputStream& out) { switch (s.fKind) { + case Statement::kNop_Kind: + break; case Statement::kBlock_Kind: this->writeBlock((Block&) s, out); break; diff --git a/src/sksl/SkSLToken.h b/src/sksl/SkSLToken.h index 8732e80c60..874c7ebd1b 100644 --- a/src/sksl/SkSLToken.h +++ b/src/sksl/SkSLToken.h @@ -104,6 +104,7 @@ struct Token { COHERENT, VOLATILE, RESTRICT, + HASSIDEEFFECTS, STRUCT, LAYOUT, DIRECTIVE, diff --git a/src/sksl/ast/SkSLASTFunction.h b/src/sksl/ast/SkSLASTFunction.h index d9f3067baa..0dff3aeaa1 100644 --- a/src/sksl/ast/SkSLASTFunction.h +++ b/src/sksl/ast/SkSLASTFunction.h @@ -19,10 +19,11 @@ namespace SkSL { * A function declaration or definition. The fBody field will be null for declarations. */ struct ASTFunction : public ASTDeclaration { - ASTFunction(Position position, std::unique_ptr returnType, String name, - std::vector> parameters, + ASTFunction(Position position, Modifiers modifiers, std::unique_ptr returnType, + String name, std::vector> parameters, std::unique_ptr body) : INHERITED(position, kFunction_Kind) + , fModifiers(modifiers) , fReturnType(std::move(returnType)) , fName(std::move(name)) , fParameters(std::move(parameters)) @@ -44,6 +45,7 @@ struct ASTFunction : public ASTDeclaration { return result; } + const Modifiers fModifiers; const std::unique_ptr fReturnType; const String fName; const std::vector> fParameters; diff --git a/src/sksl/ir/SkSLBinaryExpression.h b/src/sksl/ir/SkSLBinaryExpression.h index 73b1829ef2..789db5783b 100644 --- a/src/sksl/ir/SkSLBinaryExpression.h +++ b/src/sksl/ir/SkSLBinaryExpression.h @@ -26,15 +26,19 @@ struct BinaryExpression : public Expression { , fOperator(op) , fRight(std::move(right)) {} - virtual std::unique_ptr constantPropagate( - const IRGenerator& irGenerator, - const DefinitionMap& definitions) override { + std::unique_ptr constantPropagate(const IRGenerator& irGenerator, + const DefinitionMap& definitions) override { return irGenerator.constantFold(*fLeft, fOperator, *fRight); } - virtual String description() const override { + bool hasSideEffects() const override { + return Token::IsAssignment(fOperator) || fLeft->hasSideEffects() || + fRight->hasSideEffects(); + } + + String description() const override { return "(" + fLeft->description() + " " + Token::OperatorName(fOperator) + " " + fRight->description() + ")"; } diff --git a/src/sksl/ir/SkSLBlock.h b/src/sksl/ir/SkSLBlock.h index fe58d44135..11976660b7 100644 --- a/src/sksl/ir/SkSLBlock.h +++ b/src/sksl/ir/SkSLBlock.h @@ -23,6 +23,15 @@ struct Block : public Statement { , fSymbols(std::move(symbols)) , fStatements(std::move(statements)) {} + bool isEmpty() const override { + for (const auto& s : fStatements) { + if (!s->isEmpty()) { + return false; + } + } + return true; + } + String description() const override { String result("{"); for (size_t i = 0; i < fStatements.size(); i++) { @@ -36,7 +45,7 @@ struct Block : public Statement { // it's important to keep fStatements defined after (and thus destroyed before) fSymbols, // because destroying statements can modify reference counts in symbols const std::shared_ptr fSymbols; - const std::vector> fStatements; + std::vector> fStatements; typedef Statement INHERITED; }; diff --git a/src/sksl/ir/SkSLBoolLiteral.h b/src/sksl/ir/SkSLBoolLiteral.h index 4e1e050778..13203a4e55 100644 --- a/src/sksl/ir/SkSLBoolLiteral.h +++ b/src/sksl/ir/SkSLBoolLiteral.h @@ -25,6 +25,10 @@ struct BoolLiteral : public Expression { return String(fValue ? "true" : "false"); } + bool hasSideEffects() const override { + return false; + } + bool isConstant() const override { return true; } diff --git a/src/sksl/ir/SkSLConstructor.h b/src/sksl/ir/SkSLConstructor.h index 5c647c7cab..208031abba 100644 --- a/src/sksl/ir/SkSLConstructor.h +++ b/src/sksl/ir/SkSLConstructor.h @@ -30,20 +30,36 @@ struct Constructor : public Expression { : INHERITED(position, kConstructor_Kind, type) , fArguments(std::move(arguments)) {} - virtual std::unique_ptr constantPropagate( - const IRGenerator& irGenerator, - const DefinitionMap& definitions) override { - if (fArguments.size() == 1 && fArguments[0]->fKind == Expression::kIntLiteral_Kind && - // promote float(1) to 1.0 - fType == *irGenerator.fContext.fFloat_Type) { - int64_t intValue = ((IntLiteral&) *fArguments[0]).fValue; - return std::unique_ptr(new FloatLiteral(irGenerator.fContext, - fPosition, - intValue)); + std::unique_ptr constantPropagate(const IRGenerator& irGenerator, + const DefinitionMap& definitions) override { + if (fArguments.size() == 1 && fArguments[0]->fKind == Expression::kIntLiteral_Kind) { + if (fType == *irGenerator.fContext.fFloat_Type) { + // promote float(1) to 1.0 + int64_t intValue = ((IntLiteral&) *fArguments[0]).fValue; + return std::unique_ptr(new FloatLiteral(irGenerator.fContext, + fPosition, + intValue)); + } else if (fType == *irGenerator.fContext.fUInt_Type) { + // promote uint(1) to 1u + int64_t intValue = ((IntLiteral&) *fArguments[0]).fValue; + return std::unique_ptr(new IntLiteral(irGenerator.fContext, + fPosition, + intValue, + &fType)); + } } return nullptr; } + bool hasSideEffects() const override { + for (const auto& arg : fArguments) { + if (arg->hasSideEffects()) { + return true; + } + } + return false; + } + String description() const override { String result = fType.description() + "("; String separator; @@ -65,6 +81,43 @@ struct Constructor : public Expression { return true; } + const Expression& getVecComponent(int index) const { + ASSERT(fType.kind() == Type::kVector_Kind); + if (fArguments.size() == 1 && fArguments[0]->fType.kind() == Type::kScalar_Kind) { + return *fArguments[0]; + } + int current = 0; + for (const auto& arg : fArguments) { + ASSERT(current <= index); + if (arg->fType.kind() == Type::kScalar_Kind) { + if (index == current) { + return *arg; + } + current++; + } else { + ASSERT(arg->fType.kind() == Type::kVector_Kind); + ASSERT(arg->fKind == Expression::kConstructor_Kind); + if (current + arg->fType.columns() > index) { + return ((const Constructor&) *arg).getVecComponent(index - current); + } + current += arg->fType.columns(); + } + } + ABORT("failed to find vector component %d in %s\n", index, description().c_str()); + } + + double getFVecComponent(int index) const { + const Expression& c = this->getVecComponent(index); + ASSERT(c.fKind == Expression::kFloatLiteral_Kind); + return ((FloatLiteral&) c).fValue; + } + + int64_t getIVecComponent(int index) const { + const Expression& c = this->getVecComponent(index); + ASSERT(c.fKind == Expression::kIntLiteral_Kind); + return ((IntLiteral&) c).fValue; + } + std::vector> fArguments; typedef Expression INHERITED; diff --git a/src/sksl/ir/SkSLDoStatement.h b/src/sksl/ir/SkSLDoStatement.h index 4d3d34864d..f1ecd9a8bf 100644 --- a/src/sksl/ir/SkSLDoStatement.h +++ b/src/sksl/ir/SkSLDoStatement.h @@ -27,7 +27,7 @@ struct DoStatement : public Statement { return "do " + fStatement->description() + " while (" + fTest->description() + ");"; } - const std::unique_ptr fStatement; + std::unique_ptr fStatement; std::unique_ptr fTest; typedef Statement INHERITED; diff --git a/src/sksl/ir/SkSLExpression.h b/src/sksl/ir/SkSLExpression.h index f87d810fc0..5db9ddf96f 100644 --- a/src/sksl/ir/SkSLExpression.h +++ b/src/sksl/ir/SkSLExpression.h @@ -52,6 +52,13 @@ struct Expression : public IRNode { return false; } + /** + * Returns true if evaluating the expression potentially has side effects. Expressions may never + * return false if they actually have side effects, but it is legal (though suboptimal) to + * return true if there are not actually any side effects. + */ + virtual bool hasSideEffects() const = 0; + /** * Given a map of known constant variable values, substitute them in for references to those * variables occurring in this expression and its subexpressions. Similar simplifications, such diff --git a/src/sksl/ir/SkSLFieldAccess.h b/src/sksl/ir/SkSLFieldAccess.h index eead41c71f..e0a335f528 100644 --- a/src/sksl/ir/SkSLFieldAccess.h +++ b/src/sksl/ir/SkSLFieldAccess.h @@ -31,7 +31,11 @@ struct FieldAccess : public Expression { , fFieldIndex(fieldIndex) , fOwnerKind(ownerKind) {} - virtual String description() const override { + bool hasSideEffects() const override { + return fBase->hasSideEffects(); + } + + String description() const override { return fBase->description() + "." + fBase->fType.fields()[fFieldIndex].fName; } diff --git a/src/sksl/ir/SkSLFloatLiteral.h b/src/sksl/ir/SkSLFloatLiteral.h index 5ed123575b..8f83e2866c 100644 --- a/src/sksl/ir/SkSLFloatLiteral.h +++ b/src/sksl/ir/SkSLFloatLiteral.h @@ -17,14 +17,19 @@ namespace SkSL { * A literal floating point number. */ struct FloatLiteral : public Expression { - FloatLiteral(const Context& context, Position position, double value) - : INHERITED(position, kFloatLiteral_Kind, *context.fFloat_Type) + FloatLiteral(const Context& context, Position position, double value, + const Type* type = nullptr) + : INHERITED(position, kFloatLiteral_Kind, type ? *type : *context.fFloat_Type) , fValue(value) {} - virtual String description() const override { + String description() const override { return to_string(fValue); } + bool hasSideEffects() const override { + return false; + } + bool isConstant() const override { return true; } diff --git a/src/sksl/ir/SkSLForStatement.h b/src/sksl/ir/SkSLForStatement.h index b72c26b179..ca3e6cfb7a 100644 --- a/src/sksl/ir/SkSLForStatement.h +++ b/src/sksl/ir/SkSLForStatement.h @@ -48,10 +48,10 @@ struct ForStatement : public Statement { // it's important to keep fSymbols defined first (and thus destroyed last) because destroying // the other fields can update symbol reference counts const std::shared_ptr fSymbols; - const std::unique_ptr fInitializer; + std::unique_ptr fInitializer; std::unique_ptr fTest; std::unique_ptr fNext; - const std::unique_ptr fStatement; + std::unique_ptr fStatement; typedef Statement INHERITED; }; diff --git a/src/sksl/ir/SkSLFunctionCall.h b/src/sksl/ir/SkSLFunctionCall.h index 1a5c6fd693..44f8c7ed5a 100644 --- a/src/sksl/ir/SkSLFunctionCall.h +++ b/src/sksl/ir/SkSLFunctionCall.h @@ -23,6 +23,15 @@ struct FunctionCall : public Expression { , fFunction(std::move(function)) , fArguments(std::move(arguments)) {} + bool hasSideEffects() const override { + for (const auto& arg : fArguments) { + if (arg->hasSideEffects()) { + return true; + } + } + return fFunction.fModifiers.fFlags & Modifiers::kHasSideEffects_Flag; + } + String description() const override { String result = fFunction.fName + "("; String separator; diff --git a/src/sksl/ir/SkSLFunctionDeclaration.h b/src/sksl/ir/SkSLFunctionDeclaration.h index 05ba03addb..8704c9a5b0 100644 --- a/src/sksl/ir/SkSLFunctionDeclaration.h +++ b/src/sksl/ir/SkSLFunctionDeclaration.h @@ -21,11 +21,12 @@ namespace SkSL { * A function declaration (not a definition -- does not contain a body). */ struct FunctionDeclaration : public Symbol { - FunctionDeclaration(Position position, String name, + FunctionDeclaration(Position position, Modifiers modifiers, String name, std::vector parameters, const Type& returnType) : INHERITED(position, kFunctionDeclaration_Kind, std::move(name)) , fDefined(false) , fBuiltin(false) + , fModifiers(modifiers) , fParameters(std::move(parameters)) , fReturnType(returnType) {} @@ -102,6 +103,7 @@ struct FunctionDeclaration : public Symbol { mutable bool fDefined; bool fBuiltin; + Modifiers fModifiers; const std::vector fParameters; const Type& fReturnType; diff --git a/src/sksl/ir/SkSLFunctionDefinition.h b/src/sksl/ir/SkSLFunctionDefinition.h index e87ee63e7a..0277db1f07 100644 --- a/src/sksl/ir/SkSLFunctionDefinition.h +++ b/src/sksl/ir/SkSLFunctionDefinition.h @@ -19,7 +19,7 @@ namespace SkSL { */ struct FunctionDefinition : public ProgramElement { FunctionDefinition(Position position, const FunctionDeclaration& declaration, - std::unique_ptr body) + std::unique_ptr body) : INHERITED(position, kFunction_Kind) , fDeclaration(declaration) , fBody(std::move(body)) {} @@ -29,7 +29,7 @@ struct FunctionDefinition : public ProgramElement { } const FunctionDeclaration& fDeclaration; - const std::unique_ptr fBody; + std::unique_ptr fBody; typedef ProgramElement INHERITED; }; diff --git a/src/sksl/ir/SkSLFunctionReference.h b/src/sksl/ir/SkSLFunctionReference.h index 49ddf839f9..ee761c2639 100644 --- a/src/sksl/ir/SkSLFunctionReference.h +++ b/src/sksl/ir/SkSLFunctionReference.h @@ -24,7 +24,11 @@ struct FunctionReference : public Expression { : INHERITED(position, kFunctionReference_Kind, *context.fInvalid_Type) , fFunctions(function) {} - virtual String description() const override { + bool hasSideEffects() const override { + return false; + } + + String description() const override { ASSERT(false); return String(""); } diff --git a/src/sksl/ir/SkSLIfStatement.h b/src/sksl/ir/SkSLIfStatement.h index a7e0aad00e..0377b1253d 100644 --- a/src/sksl/ir/SkSLIfStatement.h +++ b/src/sksl/ir/SkSLIfStatement.h @@ -33,8 +33,9 @@ struct IfStatement : public Statement { } std::unique_ptr fTest; - const std::unique_ptr fIfTrue; - const std::unique_ptr fIfFalse; + std::unique_ptr fIfTrue; + // may be null + std::unique_ptr fIfFalse; typedef Statement INHERITED; }; diff --git a/src/sksl/ir/SkSLIndexExpression.h b/src/sksl/ir/SkSLIndexExpression.h index 68823bf184..49633b6719 100644 --- a/src/sksl/ir/SkSLIndexExpression.h +++ b/src/sksl/ir/SkSLIndexExpression.h @@ -51,6 +51,10 @@ struct IndexExpression : public Expression { ASSERT(fIndex->fType == *context.fInt_Type || fIndex->fType == *context.fUInt_Type); } + bool hasSideEffects() const override { + return fBase->hasSideEffects() || fIndex->hasSideEffects(); + } + String description() const override { return fBase->description() + "[" + fIndex->description() + "]"; } diff --git a/src/sksl/ir/SkSLIntLiteral.h b/src/sksl/ir/SkSLIntLiteral.h index 2322a3d40a..3a95ed65ba 100644 --- a/src/sksl/ir/SkSLIntLiteral.h +++ b/src/sksl/ir/SkSLIntLiteral.h @@ -23,11 +23,15 @@ struct IntLiteral : public Expression { : INHERITED(position, kIntLiteral_Kind, type ? *type : *context.fInt_Type) , fValue(value) {} - virtual String description() const override { + String description() const override { return to_string(fValue); } - bool isConstant() const override { + bool hasSideEffects() const override { + return false; + } + + bool isConstant() const override { return true; } diff --git a/src/sksl/ir/SkSLModifiers.h b/src/sksl/ir/SkSLModifiers.h index 9fae5b098c..8aaf2ae7c5 100644 --- a/src/sksl/ir/SkSLModifiers.h +++ b/src/sksl/ir/SkSLModifiers.h @@ -17,21 +17,22 @@ namespace SkSL { */ struct Modifiers { enum Flag { - kNo_Flag = 0, - kConst_Flag = 1, - kIn_Flag = 2, - kOut_Flag = 4, - kLowp_Flag = 8, - kMediump_Flag = 16, - kHighp_Flag = 32, - kUniform_Flag = 64, - kFlat_Flag = 128, - kNoPerspective_Flag = 256, - kReadOnly_Flag = 512, - kWriteOnly_Flag = 1024, - kCoherent_Flag = 2048, - kVolatile_Flag = 4096, - kRestrict_Flag = 8192 + kNo_Flag = 0, + kConst_Flag = 1 << 0, + kIn_Flag = 1 << 1, + kOut_Flag = 1 << 2, + kLowp_Flag = 1 << 3, + kMediump_Flag = 1 << 4, + kHighp_Flag = 1 << 5, + kUniform_Flag = 1 << 6, + kFlat_Flag = 1 << 7, + kNoPerspective_Flag = 1 << 8, + kReadOnly_Flag = 1 << 9, + kWriteOnly_Flag = 1 << 10, + kCoherent_Flag = 1 << 11, + kVolatile_Flag = 1 << 12, + kRestrict_Flag = 1 << 13, + kHasSideEffects_Flag = 1 << 14 }; Modifiers() @@ -80,6 +81,9 @@ struct Modifiers { if (fFlags & kRestrict_Flag) { result += "restrict "; } + if (fFlags & kHasSideEffects_Flag) { + result += "sk_has_side_effects "; + } if ((fFlags & kIn_Flag) && (fFlags & kOut_Flag)) { result += "inout "; diff --git a/src/sksl/ir/SkSLNop.h b/src/sksl/ir/SkSLNop.h new file mode 100644 index 0000000000..5ebea40583 --- /dev/null +++ b/src/sksl/ir/SkSLNop.h @@ -0,0 +1,36 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SKSL_NOP +#define SKSL_NOP + +#include "SkSLStatement.h" +#include "SkSLSymbolTable.h" + +namespace SkSL { + +/** + * A no-op statement that does nothing. + */ +struct Nop : public Statement { + Nop() + : INHERITED(Position(), kNop_Kind) {} + + virtual bool isEmpty() const override { + return true; + } + + String description() const override { + return String(";"); + } + + typedef Statement INHERITED; +}; + +} // namespace + +#endif diff --git a/src/sksl/ir/SkSLPostfixExpression.h b/src/sksl/ir/SkSLPostfixExpression.h index 2c84af72fd..e02555db70 100644 --- a/src/sksl/ir/SkSLPostfixExpression.h +++ b/src/sksl/ir/SkSLPostfixExpression.h @@ -22,7 +22,11 @@ struct PostfixExpression : public Expression { , fOperand(std::move(operand)) , fOperator(op) {} - virtual String description() const override { + bool hasSideEffects() const override { + return true; + } + + String description() const override { return fOperand->description() + Token::OperatorName(fOperator); } diff --git a/src/sksl/ir/SkSLPrefixExpression.h b/src/sksl/ir/SkSLPrefixExpression.h index 4fa54ca32d..a61ff65bd6 100644 --- a/src/sksl/ir/SkSLPrefixExpression.h +++ b/src/sksl/ir/SkSLPrefixExpression.h @@ -22,7 +22,29 @@ struct PrefixExpression : public Expression { , fOperand(std::move(operand)) , fOperator(op) {} - virtual String description() const override { + bool isConstant() const override { + return fOperator == Token::MINUS && fOperand->isConstant(); + } + + bool hasSideEffects() const override { + return fOperator == Token::PLUSPLUS || fOperator == Token::MINUSMINUS || + fOperand->hasSideEffects(); + } + + virtual std::unique_ptr constantPropagate( + const IRGenerator& irGenerator, + const DefinitionMap& definitions) override { + if (fOperand->fKind == Expression::kFloatLiteral_Kind) { + return std::unique_ptr(new FloatLiteral( + irGenerator.fContext, + Position(), + -((FloatLiteral&) *fOperand).fValue)); + + } + return nullptr; + } + + String description() const override { return Token::OperatorName(fOperator) + fOperand->description(); } diff --git a/src/sksl/ir/SkSLStatement.h b/src/sksl/ir/SkSLStatement.h index ba1a08772e..9af18eca3e 100644 --- a/src/sksl/ir/SkSLStatement.h +++ b/src/sksl/ir/SkSLStatement.h @@ -25,7 +25,9 @@ struct Statement : public IRNode { kDo_Kind, kExpression_Kind, kFor_Kind, + kGroup_Kind, kIf_Kind, + kNop_Kind, kReturn_Kind, kSwitch_Kind, kVarDeclarations_Kind, @@ -36,6 +38,10 @@ struct Statement : public IRNode { : INHERITED(position) , fKind(kind) {} + virtual bool isEmpty() const { + return false; + } + const Kind fKind; typedef IRNode INHERITED; diff --git a/src/sksl/ir/SkSLSwizzle.h b/src/sksl/ir/SkSLSwizzle.h index 1725ec2b5a..dedb81c01d 100644 --- a/src/sksl/ir/SkSLSwizzle.h +++ b/src/sksl/ir/SkSLSwizzle.h @@ -69,6 +69,34 @@ struct Swizzle : public Expression { ASSERT(fComponents.size() >= 1 && fComponents.size() <= 4); } + virtual std::unique_ptr constantPropagate( + const IRGenerator& irGenerator, + const DefinitionMap& definitions) override { + + if (fBase->fKind == Expression::kConstructor_Kind && fBase->isConstant()) { + // we're swizzling a constant vector, e.g. vec4(1).x. Simplify it. + ASSERT(fBase->fKind == Expression::kConstructor_Kind); + if (fType == *irGenerator.fContext.fInt_Type) { + ASSERT(fComponents.size() == 1); + int64_t value = ((Constructor&) *fBase).getIVecComponent(fComponents[0]); + return std::unique_ptr(new IntLiteral(irGenerator.fContext, + Position(), + value)); + } else if (fType == *irGenerator.fContext.fFloat_Type) { + ASSERT(fComponents.size() == 1); + double value = ((Constructor&) *fBase).getFVecComponent(fComponents[0]); + return std::unique_ptr(new FloatLiteral(irGenerator.fContext, + Position(), + value)); + } + } + return nullptr; + } + + bool hasSideEffects() const override { + return fBase->hasSideEffects(); + } + String description() const override { String result = fBase->description() + "."; for (int x : fComponents) { diff --git a/src/sksl/ir/SkSLTernaryExpression.h b/src/sksl/ir/SkSLTernaryExpression.h index 9fbac19c25..567af56e8e 100644 --- a/src/sksl/ir/SkSLTernaryExpression.h +++ b/src/sksl/ir/SkSLTernaryExpression.h @@ -26,6 +26,10 @@ struct TernaryExpression : public Expression { ASSERT(fIfTrue->fType == fIfFalse->fType); } + bool hasSideEffects() const override { + return fTest->hasSideEffects() || fIfTrue->hasSideEffects() || fIfFalse->hasSideEffects(); + } + String description() const override { return "(" + fTest->description() + " ? " + fIfTrue->description() + " : " + fIfFalse->description() + ")"; diff --git a/src/sksl/ir/SkSLTypeReference.h b/src/sksl/ir/SkSLTypeReference.h index b12c185ce2..eae19897c7 100644 --- a/src/sksl/ir/SkSLTypeReference.h +++ b/src/sksl/ir/SkSLTypeReference.h @@ -22,6 +22,10 @@ struct TypeReference : public Expression { : INHERITED(position, kTypeReference_Kind, *context.fInvalid_Type) , fValue(type) {} + bool hasSideEffects() const override { + return false; + } + String description() const override { return fValue.name(); } diff --git a/src/sksl/ir/SkSLUnresolvedFunction.h b/src/sksl/ir/SkSLUnresolvedFunction.h index c5fdbd0734..b222bc3053 100644 --- a/src/sksl/ir/SkSLUnresolvedFunction.h +++ b/src/sksl/ir/SkSLUnresolvedFunction.h @@ -26,7 +26,7 @@ struct UnresolvedFunction : public Symbol { #endif } - virtual String description() const override { + String description() const override { return fName; } diff --git a/src/sksl/ir/SkSLVarDeclarations.h b/src/sksl/ir/SkSLVarDeclarations.h index 5a006bd133..dbf2928d49 100644 --- a/src/sksl/ir/SkSLVarDeclarations.h +++ b/src/sksl/ir/SkSLVarDeclarations.h @@ -52,8 +52,8 @@ struct VarDeclaration { * A variable declaration statement, which may consist of one or more individual variables. */ struct VarDeclarations : public ProgramElement { - VarDeclarations(Position position, const Type* baseType, - std::vector vars) + VarDeclarations(Position position, const Type* baseType, + std::vector> vars) : INHERITED(position, kVar_Kind) , fBaseType(*baseType) , fVars(std::move(vars)) {} @@ -62,18 +62,18 @@ struct VarDeclarations : public ProgramElement { if (!fVars.size()) { return String(); } - String result = fVars[0].fVar->fModifiers.description() + fBaseType.description() + " "; + String result = fVars[0]->fVar->fModifiers.description() + fBaseType.description() + " "; String separator; for (const auto& var : fVars) { result += separator; separator = ", "; - result += var.description(); + result += var->description(); } return result; } const Type& fBaseType; - std::vector fVars; + std::vector> fVars; typedef ProgramElement INHERITED; }; diff --git a/src/sksl/ir/SkSLVariable.h b/src/sksl/ir/SkSLVariable.h index 21f17bad8e..05bba20a83 100644 --- a/src/sksl/ir/SkSLVariable.h +++ b/src/sksl/ir/SkSLVariable.h @@ -40,6 +40,10 @@ struct Variable : public Symbol { return fModifiers.description() + fType.fName + " " + fName; } + bool dead() const { + return !fWriteCount || (!fReadCount && !(fModifiers.fFlags & Modifiers::kOut_Flag)); + } + mutable Modifiers fModifiers; const Type& fType; const Storage fStorage; diff --git a/src/sksl/ir/SkSLVariableReference.h b/src/sksl/ir/SkSLVariableReference.h index af181f84fd..3b8ebe3617 100644 --- a/src/sksl/ir/SkSLVariableReference.h +++ b/src/sksl/ir/SkSLVariableReference.h @@ -41,7 +41,7 @@ struct VariableReference : public Expression { } } - virtual ~VariableReference() override { + ~VariableReference() override { if (fRefKind != kWrite_RefKind) { fVariable.fReadCount--; } @@ -67,39 +67,63 @@ struct VariableReference : public Expression { fRefKind = refKind; } + bool hasSideEffects() const override { + return false; + } + String description() const override { return fVariable.fName; } - virtual std::unique_ptr constantPropagate( - const IRGenerator& irGenerator, - const DefinitionMap& definitions) override { - auto exprIter = definitions.find(&fVariable); - if (exprIter != definitions.end() && exprIter->second) { - const Expression* expr = exprIter->second->get(); - switch (expr->fKind) { - case Expression::kIntLiteral_Kind: - return std::unique_ptr(new IntLiteral( - irGenerator.fContext, - Position(), - ((IntLiteral*) expr)->fValue)); - case Expression::kFloatLiteral_Kind: - return std::unique_ptr(new FloatLiteral( - irGenerator.fContext, + static std::unique_ptr copy_constant(const IRGenerator& irGenerator, + const Expression* expr) { + ASSERT(expr->isConstant()); + switch (expr->fKind) { + case Expression::kIntLiteral_Kind: + return std::unique_ptr(new IntLiteral( + irGenerator.fContext, + Position(), + ((IntLiteral*) expr)->fValue)); + case Expression::kFloatLiteral_Kind: + return std::unique_ptr(new FloatLiteral( + irGenerator.fContext, + Position(), + ((FloatLiteral*) expr)->fValue)); + case Expression::kBoolLiteral_Kind: + return std::unique_ptr(new BoolLiteral(irGenerator.fContext, Position(), - ((FloatLiteral*) expr)->fValue)); - default: - break; + ((BoolLiteral*) expr)->fValue)); + case Expression::kConstructor_Kind: { + const Constructor* c = (const Constructor*) expr; + std::vector> args; + for (const auto& arg : c->fArguments) { + args.push_back(copy_constant(irGenerator, arg.get())); + } + return std::unique_ptr(new Constructor(Position(), c->fType, + std::move(args))); } + default: + ABORT("unsupported constant\n"); + } + } + + std::unique_ptr constantPropagate(const IRGenerator& irGenerator, + const DefinitionMap& definitions) override { + if (fRefKind != kRead_RefKind) { + return nullptr; + } + auto exprIter = definitions.find(&fVariable); + if (exprIter != definitions.end() && exprIter->second && + (*exprIter->second)->isConstant()) { + return copy_constant(irGenerator, exprIter->second->get()); } return nullptr; } const Variable& fVariable; - -private: RefKind fRefKind; +private: typedef Expression INHERITED; }; diff --git a/src/sksl/ir/SkSLWhileStatement.h b/src/sksl/ir/SkSLWhileStatement.h index c35d6df9e4..6df1619a56 100644 --- a/src/sksl/ir/SkSLWhileStatement.h +++ b/src/sksl/ir/SkSLWhileStatement.h @@ -28,7 +28,7 @@ struct WhileStatement : public Statement { } std::unique_ptr fTest; - const std::unique_ptr fStatement; + std::unique_ptr fStatement; typedef Statement INHERITED; }; diff --git a/src/sksl/lex.sksl.c b/src/sksl/lex.sksl.c index ad08251eb9..3ad903436a 100644 --- a/src/sksl/lex.sksl.c +++ b/src/sksl/lex.sksl.c @@ -424,8 +424,8 @@ static void yynoreturn yy_fatal_error ( const char* msg , yyscan_t yyscanner ); yyg->yy_hold_char = *yy_cp; \ *yy_cp = '\0'; \ yyg->yy_c_buf_p = yy_cp; -#define YY_NUM_RULES 92 -#define YY_END_OF_BUFFER 93 +#define YY_NUM_RULES 93 +#define YY_END_OF_BUFFER 94 /* This struct is not used in this scanner, but its presence is necessary. */ struct yy_trans_info @@ -433,36 +433,37 @@ struct yy_trans_info flex_int32_t yy_verify; flex_int32_t yy_nxt; }; -static const flex_int16_t yy_accept[253] = +static const flex_int16_t yy_accept[271] = { 0, - 0, 0, 93, 91, 90, 90, 64, 91, 38, 54, - 59, 40, 41, 52, 50, 47, 51, 46, 53, 4, - 4, 66, 87, 71, 67, 70, 65, 44, 45, 58, - 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, - 38, 38, 38, 38, 38, 38, 38, 38, 42, 57, - 43, 60, 90, 69, 39, 38, 78, 63, 83, 76, - 48, 74, 49, 75, 1, 0, 88, 77, 2, 4, - 0, 0, 55, 73, 68, 72, 56, 82, 62, 38, - 38, 38, 38, 38, 12, 38, 38, 38, 38, 38, - 8, 20, 38, 38, 38, 38, 38, 38, 38, 38, - - 38, 38, 38, 38, 38, 38, 81, 61, 39, 86, - 0, 0, 0, 88, 1, 0, 0, 3, 5, 79, - 80, 85, 38, 38, 38, 38, 38, 38, 38, 38, - 38, 10, 38, 38, 38, 38, 38, 38, 21, 38, - 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, - 84, 0, 1, 89, 0, 0, 2, 38, 14, 38, - 38, 38, 38, 38, 9, 38, 28, 38, 38, 38, - 25, 38, 38, 38, 38, 38, 38, 38, 38, 6, - 38, 38, 38, 38, 0, 1, 16, 38, 24, 38, - 38, 38, 7, 27, 22, 38, 38, 38, 38, 38, - - 38, 38, 38, 38, 38, 38, 11, 38, 38, 38, - 38, 38, 36, 38, 38, 38, 38, 38, 19, 35, - 13, 38, 38, 38, 38, 38, 15, 18, 26, 38, - 38, 38, 38, 23, 38, 38, 32, 17, 38, 38, - 30, 34, 33, 38, 38, 37, 31, 38, 38, 38, - 29, 0 + 0, 0, 94, 92, 91, 91, 65, 92, 39, 55, + 60, 41, 42, 53, 51, 48, 52, 47, 54, 4, + 4, 67, 88, 72, 68, 71, 66, 45, 46, 59, + 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, + 39, 39, 39, 39, 39, 39, 39, 39, 43, 58, + 44, 61, 91, 70, 40, 39, 79, 64, 84, 77, + 49, 75, 50, 76, 1, 0, 89, 78, 2, 4, + 0, 0, 56, 74, 69, 73, 57, 83, 63, 39, + 39, 39, 39, 39, 12, 39, 39, 39, 39, 39, + 8, 20, 39, 39, 39, 39, 39, 39, 39, 39, + + 39, 39, 39, 39, 39, 39, 39, 82, 62, 40, + 87, 0, 0, 0, 89, 1, 0, 0, 3, 5, + 80, 81, 86, 39, 39, 39, 39, 39, 39, 39, + 39, 39, 10, 39, 39, 39, 39, 39, 39, 21, + 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, + 39, 39, 85, 0, 1, 90, 0, 0, 2, 39, + 14, 39, 39, 39, 39, 39, 9, 39, 28, 39, + 39, 39, 25, 39, 39, 39, 39, 39, 39, 39, + 39, 39, 6, 39, 39, 39, 39, 0, 1, 16, + 39, 24, 39, 39, 39, 7, 27, 22, 39, 39, + + 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, + 11, 39, 39, 39, 39, 39, 37, 39, 39, 39, + 39, 39, 19, 39, 36, 13, 39, 39, 39, 39, + 39, 15, 18, 26, 39, 39, 39, 39, 39, 23, + 39, 39, 32, 17, 39, 39, 30, 34, 39, 33, + 39, 39, 38, 39, 31, 39, 39, 39, 39, 39, + 39, 29, 39, 39, 39, 39, 39, 39, 35, 0 } ; static const YY_CHAR yy_ec[256] = @@ -476,11 +477,11 @@ static const YY_CHAR yy_ec[256] = 22, 23, 24, 1, 25, 25, 25, 25, 26, 25, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, - 27, 1, 28, 29, 6, 1, 30, 31, 32, 33, + 27, 1, 28, 29, 30, 1, 31, 32, 33, 34, - 34, 35, 36, 37, 38, 6, 39, 40, 41, 42, - 43, 44, 6, 45, 46, 47, 48, 49, 50, 51, - 52, 6, 53, 54, 55, 56, 1, 1, 1, 1, + 35, 36, 37, 38, 39, 6, 40, 41, 42, 43, + 44, 45, 6, 46, 47, 48, 49, 50, 51, 52, + 53, 6, 54, 55, 56, 57, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, @@ -497,178 +498,188 @@ static const YY_CHAR yy_ec[256] = 1, 1, 1, 1, 1 } ; -static const YY_CHAR yy_meta[57] = +static const YY_CHAR yy_meta[58] = { 0, 1, 1, 2, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4, 4, 1, 1, - 1, 1, 1, 1, 5, 5, 1, 1, 1, 5, - 5, 5, 5, 5, 5, 3, 3, 3, 3, 3, + 1, 1, 1, 1, 5, 5, 1, 1, 1, 3, + 5, 5, 5, 5, 5, 5, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 1, 1, 1, 1 + 3, 3, 3, 1, 1, 1, 1 } ; -static const flex_int16_t yy_base[259] = +static const flex_int16_t yy_base[277] = { 0, - 0, 0, 320, 321, 55, 57, 297, 0, 0, 296, - 53, 321, 321, 295, 50, 321, 49, 47, 57, 52, - 59, 321, 321, 59, 294, 60, 321, 321, 321, 62, - 270, 57, 54, 274, 59, 275, 59, 65, 278, 268, - 262, 264, 274, 57, 262, 264, 262, 53, 321, 74, - 321, 321, 103, 321, 0, 0, 321, 282, 321, 321, - 321, 321, 321, 321, 92, 292, 0, 321, 95, 99, - 118, 0, 280, 321, 321, 321, 279, 321, 278, 265, - 252, 78, 262, 250, 0, 249, 254, 263, 247, 255, - 0, 247, 237, 238, 254, 242, 238, 250, 92, 238, - - 244, 233, 242, 239, 240, 239, 321, 254, 0, 321, - 128, 264, 258, 0, 126, 136, 106, 138, 0, 321, - 321, 321, 243, 238, 237, 111, 240, 237, 234, 221, - 219, 0, 228, 216, 220, 218, 223, 226, 0, 227, - 225, 210, 208, 207, 207, 219, 217, 221, 210, 202, - 321, 144, 146, 321, 153, 151, 155, 209, 0, 202, - 199, 207, 196, 213, 0, 208, 0, 197, 193, 191, - 0, 190, 192, 198, 192, 189, 188, 200, 199, 0, - 187, 182, 194, 193, 157, 159, 0, 192, 0, 183, - 184, 178, 0, 0, 0, 175, 180, 174, 173, 176, - - 179, 174, 168, 177, 168, 174, 0, 168, 168, 161, - 161, 174, 0, 162, 161, 166, 163, 170, 0, 0, - 0, 160, 160, 157, 146, 145, 0, 0, 0, 132, - 116, 99, 102, 0, 113, 101, 0, 0, 105, 92, - 0, 0, 0, 79, 80, 0, 0, 81, 62, 32, - 0, 321, 175, 178, 181, 186, 191, 193 + 0, 0, 339, 340, 56, 58, 316, 0, 0, 315, + 54, 340, 340, 314, 51, 340, 50, 48, 58, 53, + 60, 340, 340, 60, 313, 61, 340, 340, 340, 63, + 288, 56, 54, 292, 60, 293, 54, 63, 296, 286, + 280, 282, 292, 62, 280, 282, 280, 65, 340, 74, + 340, 340, 106, 340, 0, 0, 340, 301, 340, 340, + 340, 340, 340, 340, 97, 311, 0, 340, 99, 104, + 119, 0, 299, 340, 340, 340, 298, 340, 297, 283, + 270, 97, 280, 268, 0, 267, 272, 281, 265, 273, + 0, 265, 255, 256, 272, 260, 256, 268, 95, 272, + + 255, 261, 250, 259, 256, 257, 256, 340, 272, 0, + 340, 132, 282, 276, 0, 130, 140, 110, 142, 0, + 340, 340, 340, 260, 255, 254, 114, 257, 254, 251, + 238, 236, 0, 245, 233, 237, 235, 240, 243, 0, + 244, 242, 227, 225, 235, 223, 223, 235, 233, 237, + 226, 218, 340, 146, 149, 340, 156, 154, 158, 225, + 0, 218, 215, 223, 212, 229, 0, 224, 0, 213, + 209, 207, 0, 206, 208, 214, 208, 205, 204, 218, + 215, 214, 0, 202, 197, 209, 208, 160, 162, 0, + 207, 0, 198, 199, 193, 0, 0, 0, 190, 195, + + 189, 188, 191, 194, 189, 184, 182, 191, 182, 188, + 0, 182, 182, 175, 175, 188, 0, 176, 175, 180, + 177, 184, 0, 186, 0, 0, 173, 173, 170, 164, + 176, 0, 0, 0, 175, 165, 155, 159, 159, 0, + 170, 163, 0, 0, 170, 159, 0, 0, 157, 0, + 129, 121, 0, 121, 0, 114, 116, 95, 111, 103, + 89, 0, 84, 82, 77, 73, 51, 20, 0, 340, + 178, 181, 184, 189, 194, 196 } ; -static const flex_int16_t yy_def[259] = +static const flex_int16_t yy_def[277] = { 0, - 252, 1, 252, 252, 252, 252, 252, 253, 254, 252, - 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, - 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, - 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, - 254, 254, 254, 254, 254, 254, 254, 254, 252, 252, - 252, 252, 252, 252, 255, 254, 252, 252, 252, 252, - 252, 252, 252, 252, 252, 256, 257, 252, 252, 252, - 252, 258, 252, 252, 252, 252, 252, 252, 252, 254, - 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, - 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, - - 254, 254, 254, 254, 254, 254, 252, 252, 255, 252, - 252, 256, 256, 257, 252, 252, 252, 252, 258, 252, - 252, 252, 254, 254, 254, 254, 254, 254, 254, 254, - 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, - 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, - 252, 252, 252, 252, 252, 252, 252, 254, 254, 254, - 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, - 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, - 254, 254, 254, 254, 252, 252, 254, 254, 254, 254, - 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, - - 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, - 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, - 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, - 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, - 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, - 254, 0, 252, 252, 252, 252, 252, 252 + 270, 1, 270, 270, 270, 270, 270, 271, 272, 270, + 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, + 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, + 272, 272, 272, 272, 272, 272, 272, 272, 272, 272, + 272, 272, 272, 272, 272, 272, 272, 272, 270, 270, + 270, 270, 270, 270, 273, 272, 270, 270, 270, 270, + 270, 270, 270, 270, 270, 274, 275, 270, 270, 270, + 270, 276, 270, 270, 270, 270, 270, 270, 270, 272, + 272, 272, 272, 272, 272, 272, 272, 272, 272, 272, + 272, 272, 272, 272, 272, 272, 272, 272, 272, 272, + + 272, 272, 272, 272, 272, 272, 272, 270, 270, 273, + 270, 270, 274, 274, 275, 270, 270, 270, 270, 276, + 270, 270, 270, 272, 272, 272, 272, 272, 272, 272, + 272, 272, 272, 272, 272, 272, 272, 272, 272, 272, + 272, 272, 272, 272, 272, 272, 272, 272, 272, 272, + 272, 272, 270, 270, 270, 270, 270, 270, 270, 272, + 272, 272, 272, 272, 272, 272, 272, 272, 272, 272, + 272, 272, 272, 272, 272, 272, 272, 272, 272, 272, + 272, 272, 272, 272, 272, 272, 272, 270, 270, 272, + 272, 272, 272, 272, 272, 272, 272, 272, 272, 272, + + 272, 272, 272, 272, 272, 272, 272, 272, 272, 272, + 272, 272, 272, 272, 272, 272, 272, 272, 272, 272, + 272, 272, 272, 272, 272, 272, 272, 272, 272, 272, + 272, 272, 272, 272, 272, 272, 272, 272, 272, 272, + 272, 272, 272, 272, 272, 272, 272, 272, 272, 272, + 272, 272, 272, 272, 272, 272, 272, 272, 272, 272, + 272, 272, 272, 272, 272, 272, 272, 272, 272, 0, + 270, 270, 270, 270, 270, 270 } ; -static const flex_int16_t yy_nxt[378] = +static const flex_int16_t yy_nxt[398] = { 0, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 9, 9, 28, 29, 30, 9, - 31, 32, 33, 34, 35, 9, 36, 37, 9, 38, - 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, - 9, 9, 49, 50, 51, 52, 53, 53, 53, 53, - 58, 61, 63, 65, 65, 251, 69, 66, 70, 70, - 64, 62, 67, 69, 59, 70, 70, 71, 68, 73, - 74, 76, 77, 78, 71, 71, 81, 83, 87, 105, - 79, 84, 71, 91, 93, 107, 85, 106, 88, 82, - - 92, 89, 72, 100, 53, 53, 101, 94, 65, 65, - 250, 115, 115, 69, 125, 70, 70, 111, 249, 126, - 116, 141, 118, 118, 71, 111, 248, 108, 116, 117, - 247, 117, 71, 246, 118, 118, 245, 142, 143, 152, - 244, 152, 115, 115, 153, 153, 243, 156, 242, 156, - 241, 155, 157, 157, 118, 118, 161, 162, 240, 155, - 153, 153, 153, 153, 185, 239, 185, 157, 157, 186, - 186, 157, 157, 186, 186, 186, 186, 55, 238, 55, - 56, 56, 56, 109, 109, 109, 112, 112, 112, 112, - 112, 114, 237, 114, 114, 114, 119, 119, 236, 235, - + 9, 31, 32, 33, 34, 35, 9, 36, 37, 9, + 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 9, 9, 49, 50, 51, 52, 53, 53, 53, + 53, 58, 61, 63, 65, 65, 269, 69, 66, 70, + 70, 64, 62, 67, 69, 59, 70, 70, 71, 68, + 73, 74, 76, 77, 78, 71, 81, 71, 83, 91, + 87, 79, 84, 93, 71, 108, 92, 85, 268, 82, + + 88, 100, 106, 89, 72, 267, 94, 53, 53, 101, + 107, 266, 102, 65, 65, 116, 116, 265, 69, 264, + 70, 70, 112, 263, 117, 142, 119, 119, 109, 71, + 118, 112, 118, 117, 126, 119, 119, 262, 71, 127, + 261, 143, 144, 154, 260, 154, 116, 116, 155, 155, + 259, 158, 258, 158, 257, 157, 159, 159, 119, 119, + 163, 164, 155, 155, 157, 155, 155, 188, 256, 188, + 159, 159, 189, 189, 159, 159, 189, 189, 189, 189, + 55, 255, 55, 56, 56, 56, 110, 110, 110, 113, + 113, 113, 113, 113, 115, 254, 115, 115, 115, 120, + + 120, 253, 252, 251, 250, 249, 248, 247, 246, 245, + 244, 243, 242, 241, 240, 239, 238, 237, 236, 235, 234, 233, 232, 231, 230, 229, 228, 227, 226, 225, 224, 223, 222, 221, 220, 219, 218, 217, 216, 215, 214, 213, 212, 211, 210, 209, 208, 207, 206, 205, 204, 203, 202, 201, 200, 199, 198, 197, 196, 195, - 194, 193, 192, 191, 190, 189, 188, 187, 184, 183, + 194, 193, 192, 191, 190, 187, 186, 185, 184, 183, 182, 181, 180, 179, 178, 177, 176, 175, 174, 173, - 172, 171, 170, 169, 168, 167, 166, 165, 164, 163, - 160, 159, 158, 154, 113, 151, 150, 149, 148, 147, - 146, 145, 144, 140, 139, 138, 137, 136, 135, 134, - 133, 132, 131, 130, 129, 128, 127, 124, 123, 122, - - 121, 120, 113, 110, 104, 103, 102, 99, 98, 97, - 96, 95, 90, 86, 80, 75, 60, 57, 54, 252, - 3, 252, 252, 252, 252, 252, 252, 252, 252, 252, - 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, - 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, - 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, - 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, - 252, 252, 252, 252, 252, 252, 252 + 172, 171, 170, 169, 168, 167, 166, 165, 162, 161, + 160, 156, 114, 153, 152, 151, 150, 149, 148, 147, + + 146, 145, 141, 140, 139, 138, 137, 136, 135, 134, + 133, 132, 131, 130, 129, 128, 125, 124, 123, 122, + 121, 114, 111, 105, 104, 103, 99, 98, 97, 96, + 95, 90, 86, 80, 75, 60, 57, 54, 270, 3, + 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, + 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, + 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, + 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, + 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, + 270, 270, 270, 270, 270, 270, 270 + } ; -static const flex_int16_t yy_chk[378] = +static const flex_int16_t yy_chk[398] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 5, 5, 6, 6, - 11, 15, 17, 18, 18, 250, 20, 19, 20, 20, - 17, 15, 19, 21, 11, 21, 21, 20, 19, 24, - 24, 26, 26, 30, 21, 20, 32, 33, 35, 48, - 30, 33, 21, 37, 38, 50, 33, 48, 35, 32, - - 37, 35, 20, 44, 53, 53, 44, 38, 65, 65, - 249, 69, 69, 70, 82, 70, 70, 65, 248, 82, - 69, 99, 117, 117, 70, 65, 245, 50, 69, 71, - 244, 71, 70, 240, 71, 71, 239, 99, 99, 111, - 236, 111, 115, 115, 111, 111, 235, 116, 233, 116, - 232, 115, 116, 116, 118, 118, 126, 126, 231, 115, - 152, 152, 153, 153, 155, 230, 155, 156, 156, 155, - 155, 157, 157, 185, 185, 186, 186, 253, 226, 253, - 254, 254, 254, 255, 255, 255, 256, 256, 256, 256, - 256, 257, 225, 257, 257, 257, 258, 258, 224, 223, - - 222, 218, 217, 216, 215, 214, 212, 211, 210, 209, - 208, 206, 205, 204, 203, 202, 201, 200, 199, 198, - 197, 196, 192, 191, 190, 188, 184, 183, 182, 181, - 179, 178, 177, 176, 175, 174, 173, 172, 170, 169, - 168, 166, 164, 163, 162, 161, 160, 158, 150, 149, - 148, 147, 146, 145, 144, 143, 142, 141, 140, 138, - 137, 136, 135, 134, 133, 131, 130, 129, 128, 127, - 125, 124, 123, 113, 112, 108, 106, 105, 104, 103, - 102, 101, 100, 98, 97, 96, 95, 94, 93, 92, - 90, 89, 88, 87, 86, 84, 83, 81, 80, 79, - - 77, 73, 66, 58, 47, 46, 45, 43, 42, 41, - 40, 39, 36, 34, 31, 25, 14, 10, 7, 3, - 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, - 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, - 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, - 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, - 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, - 252, 252, 252, 252, 252, 252, 252 + 1, 1, 1, 1, 1, 1, 1, 5, 5, 6, + 6, 11, 15, 17, 18, 18, 268, 20, 19, 20, + 20, 17, 15, 19, 21, 11, 21, 21, 20, 19, + 24, 24, 26, 26, 30, 21, 32, 20, 33, 37, + 35, 30, 33, 38, 21, 50, 37, 33, 267, 32, + + 35, 44, 48, 35, 20, 266, 38, 53, 53, 44, + 48, 265, 44, 65, 65, 69, 69, 264, 70, 263, + 70, 70, 65, 261, 69, 99, 118, 118, 50, 70, + 71, 65, 71, 69, 82, 71, 71, 260, 70, 82, + 259, 99, 99, 112, 258, 112, 116, 116, 112, 112, + 257, 117, 256, 117, 254, 116, 117, 117, 119, 119, + 127, 127, 154, 154, 116, 155, 155, 157, 252, 157, + 158, 158, 157, 157, 159, 159, 188, 188, 189, 189, + 271, 251, 271, 272, 272, 272, 273, 273, 273, 274, + 274, 274, 274, 274, 275, 249, 275, 275, 275, 276, + + 276, 246, 245, 242, 241, 239, 238, 237, 236, 235, + 231, 230, 229, 228, 227, 224, 222, 221, 220, 219, + 218, 216, 215, 214, 213, 212, 210, 209, 208, 207, + 206, 205, 204, 203, 202, 201, 200, 199, 195, 194, + 193, 191, 187, 186, 185, 184, 182, 181, 180, 179, + 178, 177, 176, 175, 174, 172, 171, 170, 168, 166, + 165, 164, 163, 162, 160, 152, 151, 150, 149, 148, + 147, 146, 145, 144, 143, 142, 141, 139, 138, 137, + 136, 135, 134, 132, 131, 130, 129, 128, 126, 125, + 124, 114, 113, 109, 107, 106, 105, 104, 103, 102, + + 101, 100, 98, 97, 96, 95, 94, 93, 92, 90, + 89, 88, 87, 86, 84, 83, 81, 80, 79, 77, + 73, 66, 58, 47, 46, 45, 43, 42, 41, 40, + 39, 36, 34, 31, 25, 14, 10, 7, 3, 270, + 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, + 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, + 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, + 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, + 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, + 270, 270, 270, 270, 270, 270, 270 + } ; /* Table of booleans, true if rule could match eol. */ -static const flex_int32_t yy_rule_can_match_eol[93] = +static const flex_int32_t yy_rule_can_match_eol[94] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, }; + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, }; /* The intent behind this definition is that it'll catch * any uses of REJECT which flex missed. @@ -697,7 +708,7 @@ static const flex_int32_t yy_rule_can_match_eol[93] = */ #define YY_NO_UNISTD_H 1 -#line 694 "lex.sksl.c" +#line 705 "lex.sksl.c" #define INITIAL 0 @@ -960,7 +971,7 @@ YY_DECL #line 30 "sksl.flex" -#line 957 "lex.sksl.c" +#line 968 "lex.sksl.c" while ( /*CONSTCOND*/1 ) /* loops until end-of-file is reached */ { @@ -987,13 +998,13 @@ yy_match: while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 253 ) + if ( yy_current_state >= 271 ) yy_c = yy_meta[yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; ++yy_cp; } - while ( yy_current_state != 252 ); + while ( yy_current_state != 270 ); yy_cp = yyg->yy_last_accepting_cpos; yy_current_state = yyg->yy_last_accepting_state; @@ -1198,296 +1209,301 @@ YY_RULE_SETUP case 35: YY_RULE_SETUP #line 100 "sksl.flex" -{ return SkSL::Token::STRUCT; } +{ return SkSL::Token::HASSIDEEFFECTS; } YY_BREAK case 36: YY_RULE_SETUP #line 102 "sksl.flex" -{ return SkSL::Token::LAYOUT; } +{ return SkSL::Token::STRUCT; } YY_BREAK case 37: YY_RULE_SETUP #line 104 "sksl.flex" -{ return SkSL::Token::PRECISION; } +{ return SkSL::Token::LAYOUT; } YY_BREAK case 38: YY_RULE_SETUP #line 106 "sksl.flex" -{ return SkSL::Token::IDENTIFIER; } +{ return SkSL::Token::PRECISION; } YY_BREAK case 39: YY_RULE_SETUP #line 108 "sksl.flex" -{ return SkSL::Token::DIRECTIVE; } +{ return SkSL::Token::IDENTIFIER; } YY_BREAK case 40: YY_RULE_SETUP #line 110 "sksl.flex" -{ return SkSL::Token::LPAREN; } +{ return SkSL::Token::DIRECTIVE; } YY_BREAK case 41: YY_RULE_SETUP #line 112 "sksl.flex" -{ return SkSL::Token::RPAREN; } +{ return SkSL::Token::LPAREN; } YY_BREAK case 42: YY_RULE_SETUP #line 114 "sksl.flex" -{ return SkSL::Token::LBRACE; } +{ return SkSL::Token::RPAREN; } YY_BREAK case 43: YY_RULE_SETUP #line 116 "sksl.flex" -{ return SkSL::Token::RBRACE; } +{ return SkSL::Token::LBRACE; } YY_BREAK case 44: YY_RULE_SETUP #line 118 "sksl.flex" -{ return SkSL::Token::LBRACKET; } +{ return SkSL::Token::RBRACE; } YY_BREAK case 45: YY_RULE_SETUP #line 120 "sksl.flex" -{ return SkSL::Token::RBRACKET; } +{ return SkSL::Token::LBRACKET; } YY_BREAK case 46: YY_RULE_SETUP #line 122 "sksl.flex" -{ return SkSL::Token::DOT; } +{ return SkSL::Token::RBRACKET; } YY_BREAK case 47: YY_RULE_SETUP #line 124 "sksl.flex" -{ return SkSL::Token::COMMA; } +{ return SkSL::Token::DOT; } YY_BREAK case 48: YY_RULE_SETUP #line 126 "sksl.flex" -{ return SkSL::Token::PLUSPLUS; } +{ return SkSL::Token::COMMA; } YY_BREAK case 49: YY_RULE_SETUP #line 128 "sksl.flex" -{ return SkSL::Token::MINUSMINUS; } +{ return SkSL::Token::PLUSPLUS; } YY_BREAK case 50: YY_RULE_SETUP #line 130 "sksl.flex" -{ return SkSL::Token::PLUS; } +{ return SkSL::Token::MINUSMINUS; } YY_BREAK case 51: YY_RULE_SETUP #line 132 "sksl.flex" -{ return SkSL::Token::MINUS; } +{ return SkSL::Token::PLUS; } YY_BREAK case 52: YY_RULE_SETUP #line 134 "sksl.flex" -{ return SkSL::Token::STAR; } +{ return SkSL::Token::MINUS; } YY_BREAK case 53: YY_RULE_SETUP #line 136 "sksl.flex" -{ return SkSL::Token::SLASH; } +{ return SkSL::Token::STAR; } YY_BREAK case 54: YY_RULE_SETUP #line 138 "sksl.flex" -{ return SkSL::Token::PERCENT; } +{ return SkSL::Token::SLASH; } YY_BREAK case 55: YY_RULE_SETUP #line 140 "sksl.flex" -{ return SkSL::Token::SHL; } +{ return SkSL::Token::PERCENT; } YY_BREAK case 56: YY_RULE_SETUP #line 142 "sksl.flex" -{ return SkSL::Token::SHR; } +{ return SkSL::Token::SHL; } YY_BREAK case 57: YY_RULE_SETUP #line 144 "sksl.flex" -{ return SkSL::Token::BITWISEOR; } +{ return SkSL::Token::SHR; } YY_BREAK case 58: YY_RULE_SETUP #line 146 "sksl.flex" -{ return SkSL::Token::BITWISEXOR; } +{ return SkSL::Token::BITWISEOR; } YY_BREAK case 59: YY_RULE_SETUP #line 148 "sksl.flex" -{ return SkSL::Token::BITWISEAND; } +{ return SkSL::Token::BITWISEXOR; } YY_BREAK case 60: YY_RULE_SETUP #line 150 "sksl.flex" -{ return SkSL::Token::BITWISENOT; } +{ return SkSL::Token::BITWISEAND; } YY_BREAK case 61: YY_RULE_SETUP #line 152 "sksl.flex" -{ return SkSL::Token::LOGICALOR; } +{ return SkSL::Token::BITWISENOT; } YY_BREAK case 62: YY_RULE_SETUP #line 154 "sksl.flex" -{ return SkSL::Token::LOGICALXOR; } +{ return SkSL::Token::LOGICALOR; } YY_BREAK case 63: YY_RULE_SETUP #line 156 "sksl.flex" -{ return SkSL::Token::LOGICALAND; } +{ return SkSL::Token::LOGICALXOR; } YY_BREAK case 64: YY_RULE_SETUP #line 158 "sksl.flex" -{ return SkSL::Token::LOGICALNOT; } +{ return SkSL::Token::LOGICALAND; } YY_BREAK case 65: YY_RULE_SETUP #line 160 "sksl.flex" -{ return SkSL::Token::QUESTION; } +{ return SkSL::Token::LOGICALNOT; } YY_BREAK case 66: YY_RULE_SETUP #line 162 "sksl.flex" -{ return SkSL::Token::COLON; } +{ return SkSL::Token::QUESTION; } YY_BREAK case 67: YY_RULE_SETUP #line 164 "sksl.flex" -{ return SkSL::Token::EQ; } +{ return SkSL::Token::COLON; } YY_BREAK case 68: YY_RULE_SETUP #line 166 "sksl.flex" -{ return SkSL::Token::EQEQ; } +{ return SkSL::Token::EQ; } YY_BREAK case 69: YY_RULE_SETUP #line 168 "sksl.flex" -{ return SkSL::Token::NEQ; } +{ return SkSL::Token::EQEQ; } YY_BREAK case 70: YY_RULE_SETUP #line 170 "sksl.flex" -{ return SkSL::Token::GT; } +{ return SkSL::Token::NEQ; } YY_BREAK case 71: YY_RULE_SETUP #line 172 "sksl.flex" -{ return SkSL::Token::LT; } +{ return SkSL::Token::GT; } YY_BREAK case 72: YY_RULE_SETUP #line 174 "sksl.flex" -{ return SkSL::Token::GTEQ; } +{ return SkSL::Token::LT; } YY_BREAK case 73: YY_RULE_SETUP #line 176 "sksl.flex" -{ return SkSL::Token::LTEQ; } +{ return SkSL::Token::GTEQ; } YY_BREAK case 74: YY_RULE_SETUP #line 178 "sksl.flex" -{ return SkSL::Token::PLUSEQ; } +{ return SkSL::Token::LTEQ; } YY_BREAK case 75: YY_RULE_SETUP #line 180 "sksl.flex" -{ return SkSL::Token::MINUSEQ; } +{ return SkSL::Token::PLUSEQ; } YY_BREAK case 76: YY_RULE_SETUP #line 182 "sksl.flex" -{ return SkSL::Token::STAREQ; } +{ return SkSL::Token::MINUSEQ; } YY_BREAK case 77: YY_RULE_SETUP #line 184 "sksl.flex" -{ return SkSL::Token::SLASHEQ; } +{ return SkSL::Token::STAREQ; } YY_BREAK case 78: YY_RULE_SETUP #line 186 "sksl.flex" -{ return SkSL::Token::PERCENTEQ; } +{ return SkSL::Token::SLASHEQ; } YY_BREAK case 79: YY_RULE_SETUP #line 188 "sksl.flex" -{ return SkSL::Token::SHLEQ; } +{ return SkSL::Token::PERCENTEQ; } YY_BREAK case 80: YY_RULE_SETUP #line 190 "sksl.flex" -{ return SkSL::Token::SHREQ; } +{ return SkSL::Token::SHLEQ; } YY_BREAK case 81: YY_RULE_SETUP #line 192 "sksl.flex" -{ return SkSL::Token::BITWISEOREQ; } +{ return SkSL::Token::SHREQ; } YY_BREAK case 82: YY_RULE_SETUP #line 194 "sksl.flex" -{ return SkSL::Token::BITWISEXOREQ; } +{ return SkSL::Token::BITWISEOREQ; } YY_BREAK case 83: YY_RULE_SETUP #line 196 "sksl.flex" -{ return SkSL::Token::BITWISEANDEQ; } +{ return SkSL::Token::BITWISEXOREQ; } YY_BREAK case 84: YY_RULE_SETUP #line 198 "sksl.flex" -{ return SkSL::Token::LOGICALOREQ; } +{ return SkSL::Token::BITWISEANDEQ; } YY_BREAK case 85: YY_RULE_SETUP #line 200 "sksl.flex" -{ return SkSL::Token::LOGICALXOREQ; } +{ return SkSL::Token::LOGICALOREQ; } YY_BREAK case 86: YY_RULE_SETUP #line 202 "sksl.flex" -{ return SkSL::Token::LOGICALANDEQ; } +{ return SkSL::Token::LOGICALXOREQ; } YY_BREAK case 87: YY_RULE_SETUP #line 204 "sksl.flex" -{ return SkSL::Token::SEMICOLON; } +{ return SkSL::Token::LOGICALANDEQ; } YY_BREAK case 88: YY_RULE_SETUP #line 206 "sksl.flex" -/* line comment */ +{ return SkSL::Token::SEMICOLON; } YY_BREAK case 89: -/* rule 89 can match eol */ YY_RULE_SETUP #line 208 "sksl.flex" -/* block comment */ +/* line comment */ YY_BREAK case 90: /* rule 90 can match eol */ YY_RULE_SETUP #line 210 "sksl.flex" -/* whitespace */ +/* block comment */ YY_BREAK case 91: +/* rule 91 can match eol */ YY_RULE_SETUP #line 212 "sksl.flex" -{ return SkSL::Token::INVALID_TOKEN; } +/* whitespace */ YY_BREAK case 92: YY_RULE_SETUP #line 214 "sksl.flex" +{ return SkSL::Token::INVALID_TOKEN; } + YY_BREAK +case 93: +YY_RULE_SETUP +#line 216 "sksl.flex" ECHO; YY_BREAK -#line 1484 "lex.sksl.c" +#line 1500 "lex.sksl.c" case YY_STATE_EOF(INITIAL): yyterminate(); @@ -1783,7 +1799,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner) while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 253 ) + if ( yy_current_state >= 271 ) yy_c = yy_meta[yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; @@ -1812,11 +1828,11 @@ static int yy_get_next_buffer (yyscan_t yyscanner) while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 253 ) + if ( yy_current_state >= 271 ) yy_c = yy_meta[yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; - yy_is_jam = (yy_current_state == 252); + yy_is_jam = (yy_current_state == 270); (void)yyg; return yy_is_jam ? 0 : yy_current_state; @@ -2664,7 +2680,7 @@ void skslfree (void * ptr , yyscan_t yyscanner) #define YYTABLES_NAME "yytables" -#line 214 "sksl.flex" +#line 216 "sksl.flex" int skslwrap(yyscan_t scanner) { diff --git a/src/sksl/sksl.flex b/src/sksl/sksl.flex index bbb106c228..2dd42251f0 100644 --- a/src/sksl/sksl.flex +++ b/src/sksl/sksl.flex @@ -97,6 +97,8 @@ volatile { return SkSL::Token::VOLATILE; } restrict { return SkSL::Token::RESTRICT; } +sk_has_side_effects { return SkSL::Token::HASSIDEEFFECTS; } + struct { return SkSL::Token::STRUCT; } layout { return SkSL::Token::LAYOUT; } diff --git a/src/sksl/sksl_frag.include b/src/sksl/sksl_frag.include index d65545da66..f1192fef59 100644 --- a/src/sksl/sksl_frag.include +++ b/src/sksl/sksl_frag.include @@ -14,7 +14,7 @@ layout(builtin=9999) vec4 gl_LastFragColor; layout(builtin=9999) vec4 gl_LastFragColorARM; layout(builtin=9999) int gl_SampleMaskIn[1]; layout(builtin=9999) out int gl_SampleMask[1]; -layout(builtin=9999) vec4 gl_SecondaryFragColorEXT; +layout(builtin=9999) out vec4 gl_SecondaryFragColorEXT; layout(location=0,index=0,builtin=10001) out vec4 sk_FragColor; diff --git a/src/sksl/sksl_geom.include b/src/sksl/sksl_geom.include index 18e779f330..e980d6bed9 100644 --- a/src/sksl/sksl_geom.include +++ b/src/sksl/sksl_geom.include @@ -16,9 +16,9 @@ out sk_PerVertex { layout(builtin=8) int sk_InvocationID; -void EmitStreamVertex(int stream); -void EndStreamPrimitive(int stream); -void EmitVertex(); -void EndPrimitive(); +sk_has_side_effects void EmitStreamVertex(int stream); +sk_has_side_effects void EndStreamPrimitive(int stream); +sk_has_side_effects void EmitVertex(); +sk_has_side_effects void EndPrimitive(); ) diff --git a/tests/SkSLGLSLTest.cpp b/tests/SkSLGLSLTest.cpp index 6151b942b3..97d7acbce9 100644 --- a/tests/SkSLGLSLTest.cpp +++ b/tests/SkSLGLSLTest.cpp @@ -11,6 +11,13 @@ #if SK_SUPPORT_GPU +// Note that the optimizer will aggressively kill dead code and substitute constants in place of +// variables, so we have to jump through a few hoops to ensure that the code in these tests has the +// necessary side-effects to remain live. In some cases we rely on the optimizer not (yet) being +// smart enough to optimize around certain constructs; as the optimizer gets smarter it will +// undoubtedly end up breaking some of these tests. That is a good thing, as long as the new code is +// equivalent! + static void test(skiatest::Reporter* r, const char* src, const SkSL::Program::Settings& settings, const char* expected, SkSL::Program::Inputs* inputs, SkSL::Program::Kind kind = SkSL::Program::kFragment_Kind) { @@ -57,7 +64,7 @@ DEF_TEST(SkSLControl, r) { "void main() {" "if (sqrt(2) > 5) { sk_FragColor = vec4(0.75); } else { discard; }" "int i = 0;" - "while (i < 10) sk_FragColor *= 0.5;" + "while (i < 10) { sk_FragColor *= 0.5; i++; }" "do { sk_FragColor += 0.01; } while (sk_FragColor.x < 0.75);" "for (int i = 0; i < 10; i++) {" "if (i % 2 == 1) break; else continue;" @@ -74,7 +81,10 @@ DEF_TEST(SkSLControl, r) { " discard;\n" " }\n" " int i = 0;\n" - " while (true) sk_FragColor *= 0.5;\n" + " while (i < 10) {\n" + " sk_FragColor *= 0.5;\n" + " i++;\n" + " }\n" " do {\n" " sk_FragColor += 0.01;\n" " } while (sk_FragColor.x < 0.75);\n" @@ -105,8 +115,8 @@ DEF_TEST(SkSLFunctions, r) { "}\n" "void main() {\n" " float x = 10.0;\n" - " bar(10.0);\n" - " sk_FragColor = vec4(10.0);\n" + " bar(x);\n" + " sk_FragColor = vec4(x);\n" "}\n"); } @@ -165,16 +175,16 @@ DEF_TEST(SkSLMatrices, r) { "mat3x4 z = x * y;" "vec3 v1 = mat3(1) * vec3(1);" "vec3 v2 = vec3(1) * mat3(1);" + "sk_FragColor = vec4(z[0].x, v1 + v2);" "}", *SkSL::ShaderCapsFactory::Default(), "#version 400\n" "out vec4 sk_FragColor;\n" "void main() {\n" - " mat2x4 x = mat2x4(1.0);\n" - " mat3x2 y = mat3x2(1.0, 0.0, 0.0, 1.0, vec2(2.0, 2.0));\n" - " mat3x4 z = x * y;\n" + " mat3x4 z = mat2x4(1.0) * mat3x2(1.0, 0.0, 0.0, 1.0, vec2(2.0, 2.0));\n" " vec3 v1 = mat3(1.0) * vec3(1.0);\n" " vec3 v2 = vec3(1.0) * mat3(1.0);\n" + " sk_FragColor = vec4(z[0].x, v1 + v2);\n" "}\n"); } @@ -289,16 +299,21 @@ DEF_TEST(SkSLVersion, r) { DEF_TEST(SkSLUsesPrecisionModifiers, r) { test(r, - "void main() { float x = 0.75; highp float y = 1; }", + "void main() { float x = 0.75; highp float y = 1; x++; y++;" + "sk_FragColor.rg = vec2(x, y); }", *SkSL::ShaderCapsFactory::Default(), "#version 400\n" "out vec4 sk_FragColor;\n" "void main() {\n" " float x = 0.75;\n" " float y = 1.0;\n" - "}\n"); + " x++;\n" + " y++;\n" + " sk_FragColor.xy = vec2(x, y);\n" + "}\n"); test(r, - "void main() { float x = 0.75; highp float y = 1; }", + "void main() { float x = 0.75; highp float y = 1; x++; y++;" + "sk_FragColor.rg = vec2(x, y); }", *SkSL::ShaderCapsFactory::UsesPrecisionModifiers(), "#version 400\n" "precision highp float;\n" @@ -306,27 +321,29 @@ DEF_TEST(SkSLUsesPrecisionModifiers, r) { "void main() {\n" " float x = 0.75;\n" " highp float y = 1.0;\n" - "}\n"); + " x++;\n" + " y++;\n" + " sk_FragColor.xy = vec2(x, y);\n" + "}\n"); } DEF_TEST(SkSLMinAbs, r) { test(r, "void main() {" "float x = -5;" - "x = min(abs(x), 6);" + "sk_FragColor.r = min(abs(x), 6);" "}", *SkSL::ShaderCapsFactory::Default(), "#version 400\n" "out vec4 sk_FragColor;\n" "void main() {\n" - " float x = -5.0;\n" - " x = min(abs(-5.0), 6.0);\n" + " sk_FragColor.x = min(abs(-5.0), 6.0);\n" "}\n"); test(r, "void main() {" "float x = -5.0;" - "x = min(abs(x), 6.0);" + "sk_FragColor.r = min(abs(x), 6.0);" "}", *SkSL::ShaderCapsFactory::CannotUseMinAndAbsTogether(), "#version 400\n" @@ -334,30 +351,29 @@ DEF_TEST(SkSLMinAbs, r) { "void main() {\n" " float minAbsHackVar0;\n" " float minAbsHackVar1;\n" - " float x = -5.0;\n" - " x = ((minAbsHackVar0 = abs(-5.0)) < (minAbsHackVar1 = 6.0) ? minAbsHackVar0 : " - "minAbsHackVar1);\n" + " sk_FragColor.x = ((minAbsHackVar0 = abs(-5.0)) < (minAbsHackVar1 = 6.0) ? " + "minAbsHackVar0 : minAbsHackVar1);\n" "}\n"); } DEF_TEST(SkSLNegatedAtan, r) { test(r, - "void main() { vec2 x = vec2(1, 2); float y = atan(x.x, -(2 * x.y)); }", + "void main() { vec2 x = vec2(sqrt(2)); sk_FragColor.r = atan(x.x, -x.y); }", *SkSL::ShaderCapsFactory::Default(), "#version 400\n" "out vec4 sk_FragColor;\n" "void main() {\n" - " vec2 x = vec2(1.0, 2.0);\n" - " float y = atan(x.x, -(2.0 * x.y));\n" + " vec2 x = vec2(sqrt(2.0));\n" + " sk_FragColor.x = atan(x.x, -x.y);\n" "}\n"); test(r, - "void main() { vec2 x = vec2(1, 2); float y = atan(x.x, -(2 * x.y)); }", + "void main() { vec2 x = vec2(sqrt(2)); sk_FragColor.r = atan(x.x, -x.y); }", *SkSL::ShaderCapsFactory::MustForceNegatedAtanParamToFloat(), "#version 400\n" "out vec4 sk_FragColor;\n" "void main() {\n" - " vec2 x = vec2(1.0, 2.0);\n" - " float y = atan(x.x, -1.0 * (2.0 * x.y));\n" + " vec2 x = vec2(sqrt(2.0));\n" + " sk_FragColor.x = atan(x.x, -1.0 * x.y);\n" "}\n"); } @@ -377,28 +393,46 @@ DEF_TEST(SkSLHex, r) { test(r, "void main() {" "int i1 = 0x0;" + "i1++;" "int i2 = 0x1234abcd;" + "i2++;" "int i3 = 0x7fffffff;" + "i3++;" "int i4 = 0xffffffff;" + "i4++;" "int i5 = -0xbeef;" + "i5++;" "uint u1 = 0x0;" + "u1++;" "uint u2 = 0x1234abcd;" + "u2++;" "uint u3 = 0x7fffffff;" + "u3++;" "uint u4 = 0xffffffff;" + "u4++;" "}", *SkSL::ShaderCapsFactory::Default(), "#version 400\n" "out vec4 sk_FragColor;\n" "void main() {\n" " int i1 = 0;\n" + " i1++;\n" " int i2 = 305441741;\n" + " i2++;\n" " int i3 = 2147483647;\n" + " i3++;\n" " int i4 = -1;\n" + " i4++;\n" " int i5 = -48879;\n" + " i5++;\n" " uint u1 = 0u;\n" + " u1++;\n" " uint u2 = 305441741u;\n" + " u2++;\n" " uint u3 = 2147483647u;\n" + " u3++;\n" " uint u4 = 4294967295u;\n" + " u4++;\n" "}\n"); } @@ -438,29 +472,29 @@ DEF_TEST(SkSLArrayConstructors, r) { DEF_TEST(SkSLDerivatives, r) { test(r, - "void main() { float x = dFdx(1); }", + "void main() { sk_FragColor.r = dFdx(1); }", *SkSL::ShaderCapsFactory::Default(), "#version 400\n" "out vec4 sk_FragColor;\n" "void main() {\n" - " float x = dFdx(1.0);\n" + " sk_FragColor.x = dFdx(1.0);\n" "}\n"); test(r, - "void main() { float x = 1; }", + "void main() { sk_FragColor.r = 1; }", *SkSL::ShaderCapsFactory::ShaderDerivativeExtensionString(), "#version 400\n" "out vec4 sk_FragColor;\n" "void main() {\n" - " float x = 1.0;\n" + " sk_FragColor.x = 1.0;\n" "}\n"); test(r, - "void main() { float x = dFdx(1); }", + "void main() { sk_FragColor.r = dFdx(1); }", *SkSL::ShaderCapsFactory::ShaderDerivativeExtensionString(), "#version 400\n" "#extension GL_OES_standard_derivatives : require\n" "out vec4 sk_FragColor;\n" "void main() {\n" - " float x = dFdx(1.0);\n" + " sk_FragColor.x = dFdx(1.0);\n" "}\n"); } @@ -468,76 +502,121 @@ DEF_TEST(SkSLConstantFolding, r) { test(r, "void main() {" "float f_add = 32 + 2;" + "sk_FragColor.r = f_add;" "float f_sub = 32 - 2;" + "sk_FragColor.r = f_sub;" "float f_mul = 32 * 2;" + "sk_FragColor.r = f_mul;" "float f_div = 32 / 2;" + "sk_FragColor.r = f_div;" "float mixed = (12 > 2.0) ? (10 * 2 / 5 + 18 - 3) : 0;" + "sk_FragColor.r = mixed;" "int i_add = 32 + 2;" + "sk_FragColor.r = i_add;" "int i_sub = 32 - 2;" + "sk_FragColor.r = i_sub;" "int i_mul = 32 * 2;" + "sk_FragColor.r = i_mul;" "int i_div = 32 / 2;" + "sk_FragColor.r = i_div;" "int i_or = 12 | 6;" + "sk_FragColor.r = i_or;" "int i_and = 254 & 7;" + "sk_FragColor.r = i_and;" "int i_xor = 2 ^ 7;" + "sk_FragColor.r = i_xor;" "int i_shl = 1 << 4;" + "sk_FragColor.r = i_shl;" "int i_shr = 128 >> 2;" + "sk_FragColor.r = i_shr;" "bool gt_it = 6 > 5;" + "sk_FragColor.r = true ? 1 : 0;" "bool gt_if = 6 > 6;" + "sk_FragColor.r = gt_if ? 1 : 0;" "bool gt_ft = 6.0 > 5.0;" + "sk_FragColor.r = gt_ft ? 1 : 0;" "bool gt_ff = 6.0 > 6.0;" + "sk_FragColor.r = gt_ff ? 1 : 0;" "bool gte_it = 6 >= 6;" + "sk_FragColor.r = gte_it ? 1 : 0;" "bool gte_if = 6 >= 7;" + "sk_FragColor.r = gte_if ? 1 : 0;" "bool gte_ft = 6.0 >= 6.0;" + "sk_FragColor.r = gte_ft ? 1 : 0;" "bool gte_ff = 6.0 >= 7.0;" + "sk_FragColor.r = gte_ff ? 1 : 0;" "bool lte_it = 6 <= 6;" + "sk_FragColor.r = lte_it ? 1 : 0;" "bool lte_if = 6 <= 5;" + "sk_FragColor.r = lte_if ? 1 : 0;" "bool lte_ft = 6.0 <= 6.0;" + "sk_FragColor.r = lte_ft ? 1 : 0;" "bool lte_ff = 6.0 <= 5.0;" + "sk_FragColor.r = lte_ff ? 1 : 0;" "bool or_t = 1 == 1 || 2 == 8;" + "sk_FragColor.r = or_t ? 1 : 0;" "bool or_f = 1 > 1 || 2 == 8;" + "sk_FragColor.r = or_f ? 1 : 0;" "bool and_t = 1 == 1 && 2 <= 8;" + "sk_FragColor.r = and_t ? 1 : 0;" "bool and_f = 1 == 2 && 2 == 8;" + "sk_FragColor.r = and_f ? 1 : 0;" "bool xor_t = 1 == 1 ^^ 1 != 1;" + "sk_FragColor.r = xor_t ? 1 : 0;" "bool xor_f = 1 == 1 ^^ 1 == 1;" + "sk_FragColor.r = xor_f ? 1 : 0;" "int ternary = 10 > 5 ? 10 : 5;" + "sk_FragColor.r = ternary;" + "sk_FragColor.r = vec4(0.5, 1, 1, 1).x;" + "sk_FragColor = vec4(vec2(1), vec2(2, 3)) + vec4(5, 6, 7, 8);" + "sk_FragColor = vec4(8, vec3(10)) - vec4(1);" + "sk_FragColor = vec4(2) * vec4(1, 2, 3, 4);" + "sk_FragColor = vec4(12) / vec4(1, 2, 3, 4);" + "sk_FragColor.r = (vec4(12) / vec4(1, 2, 3, 4)).y;" "}", *SkSL::ShaderCapsFactory::Default(), "#version 400\n" "out vec4 sk_FragColor;\n" "void main() {\n" - " float f_add = 34.0;\n" - " float f_sub = 30.0;\n" - " float f_mul = 64.0;\n" - " float f_div = 16.0;\n" - " float mixed = 19.0;\n" - " int i_add = 34;\n" - " int i_sub = 30;\n" - " int i_mul = 64;\n" - " int i_div = 16;\n" - " int i_or = 14;\n" - " int i_and = 6;\n" - " int i_xor = 5;\n" - " int i_shl = 16;\n" - " int i_shr = 32;\n" - " bool gt_it = true;\n" - " bool gt_if = false;\n" - " bool gt_ft = true;\n" - " bool gt_ff = false;\n" - " bool gte_it = true;\n" - " bool gte_if = false;\n" - " bool gte_ft = true;\n" - " bool gte_ff = false;\n" - " bool lte_it = true;\n" - " bool lte_if = false;\n" - " bool lte_ft = true;\n" - " bool lte_ff = false;\n" - " bool or_t = true;\n" - " bool or_f = false;\n" - " bool and_t = true;\n" - " bool and_f = false;\n" - " bool xor_t = true;\n" - " bool xor_f = false;\n" - " int ternary = 10;\n" + " sk_FragColor.x = 34.0;\n" + " sk_FragColor.x = 30.0;\n" + " sk_FragColor.x = 64.0;\n" + " sk_FragColor.x = 16.0;\n" + " sk_FragColor.x = 19.0;\n" + " sk_FragColor.x = 34.0;\n" + " sk_FragColor.x = 30.0;\n" + " sk_FragColor.x = 64.0;\n" + " sk_FragColor.x = 16.0;\n" + " sk_FragColor.x = 14.0;\n" + " sk_FragColor.x = 6.0;\n" + " sk_FragColor.x = 5.0;\n" + " sk_FragColor.x = 16.0;\n" + " sk_FragColor.x = 32.0;\n" + " sk_FragColor.x = 1.0;\n" + " sk_FragColor.x = 0.0;\n" + " sk_FragColor.x = 1.0;\n" + " sk_FragColor.x = 0.0;\n" + " sk_FragColor.x = 1.0;\n" + " sk_FragColor.x = 0.0;\n" + " sk_FragColor.x = 1.0;\n" + " sk_FragColor.x = 0.0;\n" + " sk_FragColor.x = 1.0;\n" + " sk_FragColor.x = 0.0;\n" + " sk_FragColor.x = 1.0;\n" + " sk_FragColor.x = 0.0;\n" + " sk_FragColor.x = 1.0;\n" + " sk_FragColor.x = 0.0;\n" + " sk_FragColor.x = 1.0;\n" + " sk_FragColor.x = 0.0;\n" + " sk_FragColor.x = 1.0;\n" + " sk_FragColor.x = 0.0;\n" + " sk_FragColor.x = 10.0;\n" + " sk_FragColor.x = 0.5;\n" + " sk_FragColor = vec4(6.0, 7.0, 9.0, 11.0);\n" + " sk_FragColor = vec4(7.0, 9.0, 9.0, 9.0);\n" + " sk_FragColor = vec4(2.0, 4.0, 6.0, 8.0);\n" + " sk_FragColor = vec4(12.0, 6.0, 4.0, 3.0);\n" + " sk_FragColor.x = 6.0;\n" "}\n"); } @@ -549,40 +628,34 @@ DEF_TEST(SkSLStaticIf, r) { "if (2 > 1) x = 2; else x = 3;" "if (1 > 2) x = 4; else x = 5;" "if (false) x = 6;" + "sk_FragColor.r = x;" "}", *SkSL::ShaderCapsFactory::Default(), "#version 400\n" "out vec4 sk_FragColor;\n" "void main() {\n" - " int x;\n" - " x = 1;\n" - " x = 2;\n" - " x = 5;\n" - " {\n" - " }\n" + " sk_FragColor.x = 5.0;\n" "}\n"); } DEF_TEST(SkSLCaps, r) { test(r, "void main() {" - "int x;" + "int x = 0;" + "int y = 0;" + "int z = 0;" + "int w = 0;" "if (sk_Caps.externalTextureSupport) x = 1;" - "if (sk_Caps.fbFetchSupport) x = 2;" - "if (sk_Caps.dropsTileOnZeroDivide && sk_Caps.texelFetchSupport) x = 3;" - "if (sk_Caps.dropsTileOnZeroDivide && sk_Caps.canUseAnyFunctionInShader) x = 4;" + "if (sk_Caps.fbFetchSupport) y = 1;" + "if (sk_Caps.dropsTileOnZeroDivide && sk_Caps.texelFetchSupport) z = 1;" + "if (sk_Caps.dropsTileOnZeroDivide && sk_Caps.canUseAnyFunctionInShader) w = 1;" + "sk_FragColor = vec4(x, y, z, w);" "}", *SkSL::ShaderCapsFactory::VariousCaps(), "#version 400\n" "out vec4 sk_FragColor;\n" "void main() {\n" - " int x;\n" - " x = 1;\n" - " {\n" - " }\n" - " x = 3;\n" - " {\n" - " }\n" + " sk_FragColor = vec4(1.0, 0.0, 1.0, 0.0);\n" "}\n"); } @@ -595,6 +668,7 @@ DEF_TEST(SkSLTexture, r) { "vec4 b = texture(two, vec2(0));" "vec4 c = texture(one, vec2(0));" "vec4 d = texture(two, vec3(0));" + "sk_FragColor = vec4(a.x, b.x, c.x, d.x);" "}", *SkSL::ShaderCapsFactory::Default(), "#version 400\n" @@ -606,6 +680,7 @@ DEF_TEST(SkSLTexture, r) { " vec4 b = texture(two, vec2(0.0));\n" " vec4 c = textureProj(one, vec2(0.0));\n" " vec4 d = textureProj(two, vec3(0.0));\n" + " sk_FragColor = vec4(a.x, b.x, c.x, d.x);\n" "}\n"); test(r, "uniform sampler1D one;" @@ -615,6 +690,7 @@ DEF_TEST(SkSLTexture, r) { "vec4 b = texture(two, vec2(0));" "vec4 c = texture(one, vec2(0));" "vec4 d = texture(two, vec3(0));" + "sk_FragColor = vec4(a.x, b.x, c.x, d.x);" "}", *SkSL::ShaderCapsFactory::Version110(), "#version 110\n" @@ -625,6 +701,7 @@ DEF_TEST(SkSLTexture, r) { " vec4 b = texture2D(two, vec2(0.0));\n" " vec4 c = texture1DProj(one, vec2(0.0));\n" " vec4 d = texture2DProj(two, vec3(0.0));\n" + " gl_FragColor = vec4(a.x, b.x, c.x, d.x);\n" "}\n"); } @@ -740,13 +817,14 @@ DEF_TEST(SkSLClipDistance, r) { DEF_TEST(SkSLArrayTypes, r) { test(r, "void main() { vec2 x[2] = vec2[2](vec2(1), vec2(2));" - "vec2[2] y = vec2[2](vec2(3), vec2(4)); }", + "vec2[2] y = vec2[2](vec2(3), vec2(4));" + "sk_FragColor = vec4(x[0], y[1]); }", *SkSL::ShaderCapsFactory::Default(), "#version 400\n" "out vec4 sk_FragColor;\n" "void main() {\n" - " vec2 x[2] = vec2[2](vec2(1.0), vec2(2.0));\n" - " vec2[2] y = vec2[2](vec2(3.0), vec2(4.0));\n" + " sk_FragColor = vec4(vec2[2](vec2(1.0), vec2(2.0))[0], " + "vec2[2](vec2(3.0), vec2(4.0))[1]);\n" "}\n"); } @@ -827,14 +905,13 @@ DEF_TEST(SkSLSwitch, r) { "#version 400\n" "out vec4 sk_FragColor;\n" "void main() {\n" - " float x;\n" " switch (2) {\n" " case 0:\n" - " x = 0.0;\n" + " ;\n" " case 1:\n" - " x = 1.0;\n" + " ;\n" " default:\n" - " x = 2.0;\n" + " ;\n" " }\n" " sk_FragColor = vec4(2.0);\n" "}\n"); @@ -903,4 +980,26 @@ DEF_TEST(SkSLRectangleTexture, r) { "}\n"); } +DEF_TEST(SkSLUnusedVars, r) { + test(r, + "void main() {" + "float a = 1, b = 2, c = 3;" + "float d = c;" + "float e = d;" + "b++;" + "d++;" + "sk_FragColor = vec4(b, b, d, d);" + "}", + *SkSL::ShaderCapsFactory::Default(), + "#version 400\n" + "out vec4 sk_FragColor;\n" + "void main() {\n" + " float b = 2.0;\n" + " float d = 3.0;\n" + " b++;\n" + " d++;\n" + " sk_FragColor = vec4(b, b, d, d);\n" + "}\n"); +} + #endif -- cgit v1.2.3