aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/sksl
diff options
context:
space:
mode:
authorGravatar Ethan Nicholas <ethannicholas@google.com>2017-04-20 19:31:52 -0400
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2017-04-20 23:57:21 +0000
commitcb67096b61f699b047fe8635984db1ac708a7b99 (patch)
tree3a8bda0962ad77d0d9ccb1d89c15f70578a7fe78 /src/sksl
parente79b473714866682dea85b66c005c5bb2ff6a397 (diff)
Improved skslc optimizer, particularly around vectors.
BUG=skia: Change-Id: Idb364d9198f2ff84aad1eb68e236fb45ec1c86b7 Reviewed-on: https://skia-review.googlesource.com/8000 Commit-Queue: Ethan Nicholas <ethannicholas@google.com> Reviewed-by: Ben Wagner <benjaminwagner@google.com>
Diffstat (limited to 'src/sksl')
-rw-r--r--src/sksl/SkSLCFGGenerator.cpp291
-rw-r--r--src/sksl/SkSLCFGGenerator.h77
-rw-r--r--src/sksl/SkSLCompiler.cpp368
-rw-r--r--src/sksl/SkSLCompiler.h27
-rw-r--r--src/sksl/SkSLContext.h4
-rw-r--r--src/sksl/SkSLGLSLCodeGenerator.cpp39
-rw-r--r--src/sksl/SkSLGLSLCodeGenerator.h2
-rw-r--r--src/sksl/SkSLIRGenerator.cpp72
-rw-r--r--src/sksl/SkSLParser.cpp10
-rw-r--r--src/sksl/SkSLSPIRVCodeGenerator.cpp12
-rw-r--r--src/sksl/SkSLToken.h1
-rw-r--r--src/sksl/ast/SkSLASTFunction.h6
-rw-r--r--src/sksl/ir/SkSLBinaryExpression.h12
-rw-r--r--src/sksl/ir/SkSLBlock.h11
-rw-r--r--src/sksl/ir/SkSLBoolLiteral.h4
-rw-r--r--src/sksl/ir/SkSLConstructor.h73
-rw-r--r--src/sksl/ir/SkSLDoStatement.h2
-rw-r--r--src/sksl/ir/SkSLExpression.h7
-rw-r--r--src/sksl/ir/SkSLFieldAccess.h6
-rw-r--r--src/sksl/ir/SkSLFloatLiteral.h11
-rw-r--r--src/sksl/ir/SkSLForStatement.h4
-rw-r--r--src/sksl/ir/SkSLFunctionCall.h9
-rw-r--r--src/sksl/ir/SkSLFunctionDeclaration.h4
-rw-r--r--src/sksl/ir/SkSLFunctionDefinition.h4
-rw-r--r--src/sksl/ir/SkSLFunctionReference.h6
-rw-r--r--src/sksl/ir/SkSLIfStatement.h5
-rw-r--r--src/sksl/ir/SkSLIndexExpression.h4
-rw-r--r--src/sksl/ir/SkSLIntLiteral.h8
-rw-r--r--src/sksl/ir/SkSLModifiers.h34
-rw-r--r--src/sksl/ir/SkSLNop.h36
-rw-r--r--src/sksl/ir/SkSLPostfixExpression.h6
-rw-r--r--src/sksl/ir/SkSLPrefixExpression.h24
-rw-r--r--src/sksl/ir/SkSLStatement.h6
-rw-r--r--src/sksl/ir/SkSLSwizzle.h28
-rw-r--r--src/sksl/ir/SkSLTernaryExpression.h4
-rw-r--r--src/sksl/ir/SkSLTypeReference.h4
-rw-r--r--src/sksl/ir/SkSLUnresolvedFunction.h2
-rw-r--r--src/sksl/ir/SkSLVarDeclarations.h10
-rw-r--r--src/sksl/ir/SkSLVariable.h4
-rw-r--r--src/sksl/ir/SkSLVariableReference.h66
-rw-r--r--src/sksl/ir/SkSLWhileStatement.h2
-rw-r--r--src/sksl/lex.sksl.c490
-rw-r--r--src/sksl/sksl.flex2
-rw-r--r--src/sksl/sksl_frag.include2
-rw-r--r--src/sksl/sksl_geom.include8
45 files changed, 1357 insertions, 450 deletions
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() : "<undefined>");
+ iter->second ? (*iter->second)->description().c_str() : "<undefined>");
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<BasicBlock::Node>::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<BasicBlock::Node>::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<BasicBlock::Node>::iterator* iter) {
+ Expression* expr = (*iter)->expression()->get();
+ switch (expr->fKind) {
+ case Expression::kBinary_Kind: {
+ BinaryExpression* b = (BinaryExpression*) expr;
+ if (b->fOperator == Token::EQ) {
+ if (!this->tryRemoveLValueBefore(iter, b->fLeft.get())) {
+ return false;
+ }
+ } else if (!this->tryRemoveExpressionBefore(iter, b->fLeft.get())) {
+ return false;
+ }
+ if (!this->tryRemoveExpressionBefore(iter, b->fRight.get())) {
+ return false;
+ }
+ 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<BasicBlock::Node>::iterator* iter,
+ std::unique_ptr<Expression>* expr) {
+ switch ((*expr)->fKind) {
+ case Expression::kBinary_Kind: {
+ BinaryExpression* b = (BinaryExpression*) expr->get();
+ if (!this->tryInsertExpression(iter, &b->fRight)) {
+ return false;
+ }
+ ++(*iter);
+ if (!this->tryInsertExpression(iter, &b->fLeft)) {
+ return false;
+ }
+ ++(*iter);
+ BasicBlock::Node node = { BasicBlock::Node::kExpression_Kind, true, expr, nullptr };
+ *iter = fNodes.insert(*iter, node);
+ return true;
+ }
+ case Expression::kBoolLiteral_Kind: // fall through
+ case Expression::kFloatLiteral_Kind: // fall through
+ case Expression::kIntLiteral_Kind: // fall through
+ case Expression::kVariableReference_Kind: {
+ BasicBlock::Node node = { BasicBlock::Node::kExpression_Kind, true, expr, nullptr };
+ *iter = fNodes.insert(*iter, node);
+ return true;
+ }
+ case Expression::kConstructor_Kind: {
+ Constructor* c = (Constructor*) expr->get();
+ for (auto& arg : c->fArguments) {
+ if (!this->tryInsertExpression(iter, &arg)) {
+ return false;
+ }
+ ++(*iter);
+ }
+ BasicBlock::Node node = { BasicBlock::Node::kExpression_Kind, true, expr, nullptr };
+ *iter = fNodes.insert(*iter, node);
+ return true;
+ }
+ default:
+ return false;
+ }
+}
+
void CFGGenerator::addExpression(CFG& cfg, std::unique_ptr<Expression>* e, bool constantPropagate) {
ASSERT(e);
switch ((*e)->fKind) {
@@ -182,6 +383,8 @@ void CFGGenerator::addExpression(CFG& cfg, std::unique_ptr<Expression>* 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<Expression>* e) {
}
}
-void CFGGenerator::addStatement(CFG& cfg, const Statement* s) {
- switch (s->fKind) {
+void CFGGenerator::addStatement(CFG& cfg, std::unique_ptr<Statement>* 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>* expression,
+ std::unique_ptr<Statement>* statement)
+ : fKind(kind)
+ , fConstantPropagation(constantPropagation)
+ , fExpression(expression)
+ , fStatement(statement) {}
+
+ std::unique_ptr<Expression>* expression() const {
+ ASSERT(fKind == kExpression_Kind);
+ return fExpression;
+ }
+
+ void setExpression(std::unique_ptr<Expression> expr) {
+ ASSERT(fKind == kExpression_Kind);
+ *fExpression = std::move(expr);
+ }
+
+ std::unique_ptr<Statement>* statement() const {
+ ASSERT(fKind == kStatement_Kind);
+ return fStatement;
+ }
+
+ void setStatement(std::unique_ptr<Statement> 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<Expression>* fExpression;
- const Statement* fStatement;
+ std::unique_ptr<Statement>* 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<BasicBlock::Node>::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<BasicBlock::Node>::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<BasicBlock::Node>::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<BasicBlock::Node>::iterator* iter,
+ std::unique_ptr<Expression>* expr);
+
std::vector<Node> fNodes;
std::set<BlockId> fEntrances;
std::set<BlockId> 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<Statement>* s);
void addExpression(CFG& cfg, std::unique_ptr<Expression>* 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<Expression>*) &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<Expression>*) &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<BlockId> 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<BasicBlock::Node>::iterator* iter,
+ std::unique_ptr<Expression>* newExpression) {
+ std::unique_ptr<Expression>* 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<BasicBlock::Node>::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<BasicBlock::Node>::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<BasicBlock::Node>::iterator* iter,
+ std::unordered_set<const Variable*>* undefinedVariables,
+ bool* outUpdated,
+ bool* outNeedsRescan) {
+ Expression* expr = (*iter)->expression()->get();
+ ASSERT(expr);
+ if ((*iter)->fConstantPropagation) {
+ std::unique_ptr<Expression> 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<BasicBlock::Node>::iterator* iter,
+ std::unordered_set<const Variable*>* 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<Statement>(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<Statement>(
+ 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<Statement>(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<Statement>(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<Statement>(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<Expression> 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<const Variable*> 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 <set>
+#include <unordered_set>
#include <vector>
#include "ir/SkSLProgram.h"
#include "ir/SkSLSymbolTable.h"
@@ -71,7 +72,31 @@ private:
void scanCFG(CFG* cfg, BlockId block, std::set<BlockId>* 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<BasicBlock::Node>::iterator* iter,
+ std::unordered_set<const Variable*>* 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<BasicBlock::Node>::iterator* iter,
+ std::unordered_set<const Variable*>* 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("<defined>");
}
+
+ 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<std::unique_ptr<Statement>>& 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<std::unique_ptr<Statement>>& 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<Statement> IRGenerator::convertVarDeclarationStatement(
std::unique_ptr<VarDeclarations> IRGenerator::convertVarDeclarations(const ASTVarDeclarations& decl,
Variable::Storage storage) {
- std::vector<VarDeclaration> variables;
+ std::vector<std::unique_ptr<VarDeclaration>> variables;
const Type* baseType = this->convertType(*decl.fType);
if (!baseType) {
return nullptr;
@@ -254,6 +254,7 @@ std::unique_ptr<VarDeclarations> 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<VarDeclarations> 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<FunctionDefinition> 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<FunctionDefinition> IRGenerator::convertFunction(const ASTFuncti
if (!decl) {
// couldn't find an existing declaration
auto newDecl = std::unique_ptr<FunctionDeclaration>(new FunctionDeclaration(f.fPosition,
+ f.fModifiers,
f.fName,
parameters,
*returnType));
@@ -590,6 +594,8 @@ std::unique_ptr<FunctionDefinition> 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<FunctionDefinition>(new FunctionDefinition(f.fPosition, *decl,
std::move(body)));
}
@@ -608,16 +614,16 @@ std::unique_ptr<InterfaceBlock> 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<Expression> 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<Expression> 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<Expression> 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<std::unique_ptr<Expression>> 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<Expression>(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<Expression> 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<ASTDeclaration> 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<std::unique_ptr<ASTParameter>> parameters;
while (this->peek().fKind != Token::RPAREN) {
@@ -334,7 +334,9 @@ std::unique_ptr<ASTDeclaration> Parser::declaration() {
return nullptr;
}
}
- return std::unique_ptr<ASTDeclaration>(new ASTFunction(name.fPosition, std::move(type),
+ return std::unique_ptr<ASTDeclaration>(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<ASTType> returnType, String name,
- std::vector<std::unique_ptr<ASTParameter>> parameters,
+ ASTFunction(Position position, Modifiers modifiers, std::unique_ptr<ASTType> returnType,
+ String name, std::vector<std::unique_ptr<ASTParameter>> parameters,
std::unique_ptr<ASTBlock> 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<ASTType> fReturnType;
const String fName;
const std::vector<std::unique_ptr<ASTParameter>> 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<Expression> constantPropagate(
- const IRGenerator& irGenerator,
- const DefinitionMap& definitions) override {
+ std::unique_ptr<Expression> 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<SymbolTable> fSymbols;
- const std::vector<std::unique_ptr<Statement>> fStatements;
+ std::vector<std::unique_ptr<Statement>> 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<Expression> 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<Expression>(new FloatLiteral(irGenerator.fContext,
- fPosition,
- intValue));
+ std::unique_ptr<Expression> 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<Expression>(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<Expression>(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<std::unique_ptr<Expression>> 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<Statement> fStatement;
+ std::unique_ptr<Statement> fStatement;
std::unique_ptr<Expression> 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
@@ -53,6 +53,13 @@ struct Expression : public IRNode {
}
/**
+ * 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
* as folding a constant binary expression down to a single value, may also be performed.
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<SymbolTable> fSymbols;
- const std::unique_ptr<Statement> fInitializer;
+ std::unique_ptr<Statement> fInitializer;
std::unique_ptr<Expression> fTest;
std::unique_ptr<Expression> fNext;
- const std::unique_ptr<Statement> fStatement;
+ std::unique_ptr<Statement> 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<const Variable*> 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<const Variable*> 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<Block> body)
+ std::unique_ptr<Statement> 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<Block> fBody;
+ std::unique_ptr<Statement> 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("<function>");
}
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<Expression> fTest;
- const std::unique_ptr<Statement> fIfTrue;
- const std::unique_ptr<Statement> fIfFalse;
+ std::unique_ptr<Statement> fIfTrue;
+ // may be null
+ std::unique_ptr<Statement> 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<Expression> constantPropagate(
+ const IRGenerator& irGenerator,
+ const DefinitionMap& definitions) override {
+ if (fOperand->fKind == Expression::kFloatLiteral_Kind) {
+ return std::unique_ptr<Expression>(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<Expression> 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<Expression>(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<Expression>(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<VarDeclaration> vars)
+ VarDeclarations(Position position, const Type* baseType,
+ std::vector<std::unique_ptr<VarDeclaration>> 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<VarDeclaration> fVars;
+ std::vector<std::unique_ptr<VarDeclaration>> 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<Expression> 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<Expression>(new IntLiteral(
- irGenerator.fContext,
- Position(),
- ((IntLiteral*) expr)->fValue));
- case Expression::kFloatLiteral_Kind:
- return std::unique_ptr<Expression>(new FloatLiteral(
- irGenerator.fContext,
+ static std::unique_ptr<Expression> copy_constant(const IRGenerator& irGenerator,
+ const Expression* expr) {
+ ASSERT(expr->isConstant());
+ switch (expr->fKind) {
+ case Expression::kIntLiteral_Kind:
+ return std::unique_ptr<Expression>(new IntLiteral(
+ irGenerator.fContext,
+ Position(),
+ ((IntLiteral*) expr)->fValue));
+ case Expression::kFloatLiteral_Kind:
+ return std::unique_ptr<Expression>(new FloatLiteral(
+ irGenerator.fContext,
+ Position(),
+ ((FloatLiteral*) expr)->fValue));
+ case Expression::kBoolLiteral_Kind:
+ return std::unique_ptr<Expression>(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<std::unique_ptr<Expression>> args;
+ for (const auto& arg : c->fArguments) {
+ args.push_back(copy_constant(irGenerator, arg.get()));
+ }
+ return std::unique_ptr<Expression>(new Constructor(Position(), c->fType,
+ std::move(args)));
}
+ default:
+ ABORT("unsupported constant\n");
+ }
+ }
+
+ std::unique_ptr<Expression> 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<Expression> fTest;
- const std::unique_ptr<Statement> fStatement;
+ std::unique_ptr<Statement> 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();
)