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>
This commit is contained in:
parent
e79b473714
commit
cb67096b61
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
// compute the data flow
|
||||
cfg.fBlocks[cfg.fStart].fBefore = compute_start_state(cfg);
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
}
|
||||
}
|
||||
this->addDefinitions(n, &definitions);
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
} while (updated);
|
||||
ASSERT(!needsRescan);
|
||||
|
||||
// check for missing return
|
||||
if (f.fDeclaration.fReturnType != *fContext.fVoid_Type) {
|
||||
|
@ -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,
|
||||
|
@ -284,6 +284,10 @@ private:
|
||||
return String("<defined>");
|
||||
}
|
||||
|
||||
bool hasSideEffects() const override {
|
||||
return false;
|
||||
}
|
||||
|
||||
typedef Expression INHERITED;
|
||||
};
|
||||
};
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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" &&
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -104,6 +104,7 @@ struct Token {
|
||||
COHERENT,
|
||||
VOLATILE,
|
||||
RESTRICT,
|
||||
HASSIDEEFFECTS,
|
||||
STRUCT,
|
||||
LAYOUT,
|
||||
DIRECTIVE,
|
||||
|
@ -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;
|
||||
|
@ -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() + ")";
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -52,6 +52,13 @@ struct Expression : public IRNode {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if evaluating the expression potentially has side effects. Expressions may never
|
||||
* return false if they actually have side effects, but it is legal (though suboptimal) to
|
||||
* return true if there are not actually any side effects.
|
||||
*/
|
||||
virtual bool hasSideEffects() const = 0;
|
||||
|
||||
/**
|
||||
* Given a map of known constant variable values, substitute them in for references to those
|
||||
* variables occurring in this expression and its subexpressions. Similar simplifications, such
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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>");
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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() + "]";
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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 ";
|
||||
|
36
src/sksl/ir/SkSLNop.h
Normal file
36
src/sksl/ir/SkSLNop.h
Normal file
@ -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
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
|
@ -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() + ")";
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -26,7 +26,7 @@ struct UnresolvedFunction : public Symbol {
|
||||
#endif
|
||||
}
|
||||
|
||||
virtual String description() const override {
|
||||
String description() const override {
|
||||
return fName;
|
||||
}
|
||||
|
||||
|
@ -53,7 +53,7 @@ struct VarDeclaration {
|
||||
*/
|
||||
struct VarDeclarations : public ProgramElement {
|
||||
VarDeclarations(Position position, const Type* baseType,
|
||||
std::vector<VarDeclaration> vars)
|
||||
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;
|
||||
};
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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,
|
||||
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,
|
||||
|
||||
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,
|
||||
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,
|
||||
|
||||
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
|
||||
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,
|
||||
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,
|
||||
|
||||
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,
|
||||
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,
|
||||
|
||||
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
|
||||
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,
|
||||
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,
|
||||
|
||||
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,
|
||||
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,
|
||||
|
||||
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
|
||||
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,
|
||||
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,
|
||||
|
||||
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,
|
||||
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,
|
||||
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
|
||||
|
||||
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
|
||||
} ;
|
||||
|
||||
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,
|
||||
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,
|
||||
|
||||
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,
|
||||
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,
|
||||
|
||||
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,
|
||||
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
|
||||
|
||||
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
|
||||
} ;
|
||||
|
||||
/* 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) {
|
||||
|
@ -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; }
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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();
|
||||
|
||||
)
|
||||
|
@ -11,6 +11,13 @@
|
||||
|
||||
#if SK_SUPPORT_GPU
|
||||
|
||||
// Note that the optimizer will aggressively kill dead code and substitute constants in place of
|
||||
// variables, so we have to jump through a few hoops to ensure that the code in these tests has the
|
||||
// necessary side-effects to remain live. In some cases we rely on the optimizer not (yet) being
|
||||
// smart enough to optimize around certain constructs; as the optimizer gets smarter it will
|
||||
// undoubtedly end up breaking some of these tests. That is a good thing, as long as the new code is
|
||||
// equivalent!
|
||||
|
||||
static void test(skiatest::Reporter* r, const char* src, const SkSL::Program::Settings& settings,
|
||||
const char* expected, SkSL::Program::Inputs* inputs,
|
||||
SkSL::Program::Kind kind = SkSL::Program::kFragment_Kind) {
|
||||
@ -57,7 +64,7 @@ DEF_TEST(SkSLControl, r) {
|
||||
"void main() {"
|
||||
"if (sqrt(2) > 5) { sk_FragColor = vec4(0.75); } else { discard; }"
|
||||
"int i = 0;"
|
||||
"while (i < 10) sk_FragColor *= 0.5;"
|
||||
"while (i < 10) { sk_FragColor *= 0.5; i++; }"
|
||||
"do { sk_FragColor += 0.01; } while (sk_FragColor.x < 0.75);"
|
||||
"for (int i = 0; i < 10; i++) {"
|
||||
"if (i % 2 == 1) break; else continue;"
|
||||
@ -74,7 +81,10 @@ DEF_TEST(SkSLControl, r) {
|
||||
" discard;\n"
|
||||
" }\n"
|
||||
" int i = 0;\n"
|
||||
" while (true) sk_FragColor *= 0.5;\n"
|
||||
" while (i < 10) {\n"
|
||||
" sk_FragColor *= 0.5;\n"
|
||||
" i++;\n"
|
||||
" }\n"
|
||||
" do {\n"
|
||||
" sk_FragColor += 0.01;\n"
|
||||
" } while (sk_FragColor.x < 0.75);\n"
|
||||
@ -105,8 +115,8 @@ DEF_TEST(SkSLFunctions, r) {
|
||||
"}\n"
|
||||
"void main() {\n"
|
||||
" float x = 10.0;\n"
|
||||
" bar(10.0);\n"
|
||||
" sk_FragColor = vec4(10.0);\n"
|
||||
" bar(x);\n"
|
||||
" sk_FragColor = vec4(x);\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
@ -165,16 +175,16 @@ DEF_TEST(SkSLMatrices, r) {
|
||||
"mat3x4 z = x * y;"
|
||||
"vec3 v1 = mat3(1) * vec3(1);"
|
||||
"vec3 v2 = vec3(1) * mat3(1);"
|
||||
"sk_FragColor = vec4(z[0].x, v1 + v2);"
|
||||
"}",
|
||||
*SkSL::ShaderCapsFactory::Default(),
|
||||
"#version 400\n"
|
||||
"out vec4 sk_FragColor;\n"
|
||||
"void main() {\n"
|
||||
" mat2x4 x = mat2x4(1.0);\n"
|
||||
" mat3x2 y = mat3x2(1.0, 0.0, 0.0, 1.0, vec2(2.0, 2.0));\n"
|
||||
" mat3x4 z = x * y;\n"
|
||||
" mat3x4 z = mat2x4(1.0) * mat3x2(1.0, 0.0, 0.0, 1.0, vec2(2.0, 2.0));\n"
|
||||
" vec3 v1 = mat3(1.0) * vec3(1.0);\n"
|
||||
" vec3 v2 = vec3(1.0) * mat3(1.0);\n"
|
||||
" sk_FragColor = vec4(z[0].x, v1 + v2);\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
@ -289,16 +299,21 @@ DEF_TEST(SkSLVersion, r) {
|
||||
|
||||
DEF_TEST(SkSLUsesPrecisionModifiers, r) {
|
||||
test(r,
|
||||
"void main() { float x = 0.75; highp float y = 1; }",
|
||||
"void main() { float x = 0.75; highp float y = 1; x++; y++;"
|
||||
"sk_FragColor.rg = vec2(x, y); }",
|
||||
*SkSL::ShaderCapsFactory::Default(),
|
||||
"#version 400\n"
|
||||
"out vec4 sk_FragColor;\n"
|
||||
"void main() {\n"
|
||||
" float x = 0.75;\n"
|
||||
" float y = 1.0;\n"
|
||||
" x++;\n"
|
||||
" y++;\n"
|
||||
" sk_FragColor.xy = vec2(x, y);\n"
|
||||
"}\n");
|
||||
test(r,
|
||||
"void main() { float x = 0.75; highp float y = 1; }",
|
||||
"void main() { float x = 0.75; highp float y = 1; x++; y++;"
|
||||
"sk_FragColor.rg = vec2(x, y); }",
|
||||
*SkSL::ShaderCapsFactory::UsesPrecisionModifiers(),
|
||||
"#version 400\n"
|
||||
"precision highp float;\n"
|
||||
@ -306,6 +321,9 @@ DEF_TEST(SkSLUsesPrecisionModifiers, r) {
|
||||
"void main() {\n"
|
||||
" float x = 0.75;\n"
|
||||
" highp float y = 1.0;\n"
|
||||
" x++;\n"
|
||||
" y++;\n"
|
||||
" sk_FragColor.xy = vec2(x, y);\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
@ -313,20 +331,19 @@ DEF_TEST(SkSLMinAbs, r) {
|
||||
test(r,
|
||||
"void main() {"
|
||||
"float x = -5;"
|
||||
"x = min(abs(x), 6);"
|
||||
"sk_FragColor.r = min(abs(x), 6);"
|
||||
"}",
|
||||
*SkSL::ShaderCapsFactory::Default(),
|
||||
"#version 400\n"
|
||||
"out vec4 sk_FragColor;\n"
|
||||
"void main() {\n"
|
||||
" float x = -5.0;\n"
|
||||
" x = min(abs(-5.0), 6.0);\n"
|
||||
" sk_FragColor.x = min(abs(-5.0), 6.0);\n"
|
||||
"}\n");
|
||||
|
||||
test(r,
|
||||
"void main() {"
|
||||
"float x = -5.0;"
|
||||
"x = min(abs(x), 6.0);"
|
||||
"sk_FragColor.r = min(abs(x), 6.0);"
|
||||
"}",
|
||||
*SkSL::ShaderCapsFactory::CannotUseMinAndAbsTogether(),
|
||||
"#version 400\n"
|
||||
@ -334,30 +351,29 @@ DEF_TEST(SkSLMinAbs, r) {
|
||||
"void main() {\n"
|
||||
" float minAbsHackVar0;\n"
|
||||
" float minAbsHackVar1;\n"
|
||||
" float x = -5.0;\n"
|
||||
" x = ((minAbsHackVar0 = abs(-5.0)) < (minAbsHackVar1 = 6.0) ? minAbsHackVar0 : "
|
||||
"minAbsHackVar1);\n"
|
||||
" sk_FragColor.x = ((minAbsHackVar0 = abs(-5.0)) < (minAbsHackVar1 = 6.0) ? "
|
||||
"minAbsHackVar0 : minAbsHackVar1);\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
DEF_TEST(SkSLNegatedAtan, r) {
|
||||
test(r,
|
||||
"void main() { vec2 x = vec2(1, 2); float y = atan(x.x, -(2 * x.y)); }",
|
||||
"void main() { vec2 x = vec2(sqrt(2)); sk_FragColor.r = atan(x.x, -x.y); }",
|
||||
*SkSL::ShaderCapsFactory::Default(),
|
||||
"#version 400\n"
|
||||
"out vec4 sk_FragColor;\n"
|
||||
"void main() {\n"
|
||||
" vec2 x = vec2(1.0, 2.0);\n"
|
||||
" float y = atan(x.x, -(2.0 * x.y));\n"
|
||||
" vec2 x = vec2(sqrt(2.0));\n"
|
||||
" sk_FragColor.x = atan(x.x, -x.y);\n"
|
||||
"}\n");
|
||||
test(r,
|
||||
"void main() { vec2 x = vec2(1, 2); float y = atan(x.x, -(2 * x.y)); }",
|
||||
"void main() { vec2 x = vec2(sqrt(2)); sk_FragColor.r = atan(x.x, -x.y); }",
|
||||
*SkSL::ShaderCapsFactory::MustForceNegatedAtanParamToFloat(),
|
||||
"#version 400\n"
|
||||
"out vec4 sk_FragColor;\n"
|
||||
"void main() {\n"
|
||||
" vec2 x = vec2(1.0, 2.0);\n"
|
||||
" float y = atan(x.x, -1.0 * (2.0 * x.y));\n"
|
||||
" vec2 x = vec2(sqrt(2.0));\n"
|
||||
" sk_FragColor.x = atan(x.x, -1.0 * x.y);\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
@ -377,28 +393,46 @@ DEF_TEST(SkSLHex, r) {
|
||||
test(r,
|
||||
"void main() {"
|
||||
"int i1 = 0x0;"
|
||||
"i1++;"
|
||||
"int i2 = 0x1234abcd;"
|
||||
"i2++;"
|
||||
"int i3 = 0x7fffffff;"
|
||||
"i3++;"
|
||||
"int i4 = 0xffffffff;"
|
||||
"i4++;"
|
||||
"int i5 = -0xbeef;"
|
||||
"i5++;"
|
||||
"uint u1 = 0x0;"
|
||||
"u1++;"
|
||||
"uint u2 = 0x1234abcd;"
|
||||
"u2++;"
|
||||
"uint u3 = 0x7fffffff;"
|
||||
"u3++;"
|
||||
"uint u4 = 0xffffffff;"
|
||||
"u4++;"
|
||||
"}",
|
||||
*SkSL::ShaderCapsFactory::Default(),
|
||||
"#version 400\n"
|
||||
"out vec4 sk_FragColor;\n"
|
||||
"void main() {\n"
|
||||
" int i1 = 0;\n"
|
||||
" i1++;\n"
|
||||
" int i2 = 305441741;\n"
|
||||
" i2++;\n"
|
||||
" int i3 = 2147483647;\n"
|
||||
" i3++;\n"
|
||||
" int i4 = -1;\n"
|
||||
" i4++;\n"
|
||||
" int i5 = -48879;\n"
|
||||
" i5++;\n"
|
||||
" uint u1 = 0u;\n"
|
||||
" u1++;\n"
|
||||
" uint u2 = 305441741u;\n"
|
||||
" u2++;\n"
|
||||
" uint u3 = 2147483647u;\n"
|
||||
" u3++;\n"
|
||||
" uint u4 = 4294967295u;\n"
|
||||
" u4++;\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
@ -438,29 +472,29 @@ DEF_TEST(SkSLArrayConstructors, r) {
|
||||
|
||||
DEF_TEST(SkSLDerivatives, r) {
|
||||
test(r,
|
||||
"void main() { float x = dFdx(1); }",
|
||||
"void main() { sk_FragColor.r = dFdx(1); }",
|
||||
*SkSL::ShaderCapsFactory::Default(),
|
||||
"#version 400\n"
|
||||
"out vec4 sk_FragColor;\n"
|
||||
"void main() {\n"
|
||||
" float x = dFdx(1.0);\n"
|
||||
" sk_FragColor.x = dFdx(1.0);\n"
|
||||
"}\n");
|
||||
test(r,
|
||||
"void main() { float x = 1; }",
|
||||
"void main() { sk_FragColor.r = 1; }",
|
||||
*SkSL::ShaderCapsFactory::ShaderDerivativeExtensionString(),
|
||||
"#version 400\n"
|
||||
"out vec4 sk_FragColor;\n"
|
||||
"void main() {\n"
|
||||
" float x = 1.0;\n"
|
||||
" sk_FragColor.x = 1.0;\n"
|
||||
"}\n");
|
||||
test(r,
|
||||
"void main() { float x = dFdx(1); }",
|
||||
"void main() { sk_FragColor.r = dFdx(1); }",
|
||||
*SkSL::ShaderCapsFactory::ShaderDerivativeExtensionString(),
|
||||
"#version 400\n"
|
||||
"#extension GL_OES_standard_derivatives : require\n"
|
||||
"out vec4 sk_FragColor;\n"
|
||||
"void main() {\n"
|
||||
" float x = dFdx(1.0);\n"
|
||||
" sk_FragColor.x = dFdx(1.0);\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
@ -468,76 +502,121 @@ DEF_TEST(SkSLConstantFolding, r) {
|
||||
test(r,
|
||||
"void main() {"
|
||||
"float f_add = 32 + 2;"
|
||||
"sk_FragColor.r = f_add;"
|
||||
"float f_sub = 32 - 2;"
|
||||
"sk_FragColor.r = f_sub;"
|
||||
"float f_mul = 32 * 2;"
|
||||
"sk_FragColor.r = f_mul;"
|
||||
"float f_div = 32 / 2;"
|
||||
"sk_FragColor.r = f_div;"
|
||||
"float mixed = (12 > 2.0) ? (10 * 2 / 5 + 18 - 3) : 0;"
|
||||
"sk_FragColor.r = mixed;"
|
||||
"int i_add = 32 + 2;"
|
||||
"sk_FragColor.r = i_add;"
|
||||
"int i_sub = 32 - 2;"
|
||||
"sk_FragColor.r = i_sub;"
|
||||
"int i_mul = 32 * 2;"
|
||||
"sk_FragColor.r = i_mul;"
|
||||
"int i_div = 32 / 2;"
|
||||
"sk_FragColor.r = i_div;"
|
||||
"int i_or = 12 | 6;"
|
||||
"sk_FragColor.r = i_or;"
|
||||
"int i_and = 254 & 7;"
|
||||
"sk_FragColor.r = i_and;"
|
||||
"int i_xor = 2 ^ 7;"
|
||||
"sk_FragColor.r = i_xor;"
|
||||
"int i_shl = 1 << 4;"
|
||||
"sk_FragColor.r = i_shl;"
|
||||
"int i_shr = 128 >> 2;"
|
||||
"sk_FragColor.r = i_shr;"
|
||||
"bool gt_it = 6 > 5;"
|
||||
"sk_FragColor.r = true ? 1 : 0;"
|
||||
"bool gt_if = 6 > 6;"
|
||||
"sk_FragColor.r = gt_if ? 1 : 0;"
|
||||
"bool gt_ft = 6.0 > 5.0;"
|
||||
"sk_FragColor.r = gt_ft ? 1 : 0;"
|
||||
"bool gt_ff = 6.0 > 6.0;"
|
||||
"sk_FragColor.r = gt_ff ? 1 : 0;"
|
||||
"bool gte_it = 6 >= 6;"
|
||||
"sk_FragColor.r = gte_it ? 1 : 0;"
|
||||
"bool gte_if = 6 >= 7;"
|
||||
"sk_FragColor.r = gte_if ? 1 : 0;"
|
||||
"bool gte_ft = 6.0 >= 6.0;"
|
||||
"sk_FragColor.r = gte_ft ? 1 : 0;"
|
||||
"bool gte_ff = 6.0 >= 7.0;"
|
||||
"sk_FragColor.r = gte_ff ? 1 : 0;"
|
||||
"bool lte_it = 6 <= 6;"
|
||||
"sk_FragColor.r = lte_it ? 1 : 0;"
|
||||
"bool lte_if = 6 <= 5;"
|
||||
"sk_FragColor.r = lte_if ? 1 : 0;"
|
||||
"bool lte_ft = 6.0 <= 6.0;"
|
||||
"sk_FragColor.r = lte_ft ? 1 : 0;"
|
||||
"bool lte_ff = 6.0 <= 5.0;"
|
||||
"sk_FragColor.r = lte_ff ? 1 : 0;"
|
||||
"bool or_t = 1 == 1 || 2 == 8;"
|
||||
"sk_FragColor.r = or_t ? 1 : 0;"
|
||||
"bool or_f = 1 > 1 || 2 == 8;"
|
||||
"sk_FragColor.r = or_f ? 1 : 0;"
|
||||
"bool and_t = 1 == 1 && 2 <= 8;"
|
||||
"sk_FragColor.r = and_t ? 1 : 0;"
|
||||
"bool and_f = 1 == 2 && 2 == 8;"
|
||||
"sk_FragColor.r = and_f ? 1 : 0;"
|
||||
"bool xor_t = 1 == 1 ^^ 1 != 1;"
|
||||
"sk_FragColor.r = xor_t ? 1 : 0;"
|
||||
"bool xor_f = 1 == 1 ^^ 1 == 1;"
|
||||
"sk_FragColor.r = xor_f ? 1 : 0;"
|
||||
"int ternary = 10 > 5 ? 10 : 5;"
|
||||
"sk_FragColor.r = ternary;"
|
||||
"sk_FragColor.r = vec4(0.5, 1, 1, 1).x;"
|
||||
"sk_FragColor = vec4(vec2(1), vec2(2, 3)) + vec4(5, 6, 7, 8);"
|
||||
"sk_FragColor = vec4(8, vec3(10)) - vec4(1);"
|
||||
"sk_FragColor = vec4(2) * vec4(1, 2, 3, 4);"
|
||||
"sk_FragColor = vec4(12) / vec4(1, 2, 3, 4);"
|
||||
"sk_FragColor.r = (vec4(12) / vec4(1, 2, 3, 4)).y;"
|
||||
"}",
|
||||
*SkSL::ShaderCapsFactory::Default(),
|
||||
"#version 400\n"
|
||||
"out vec4 sk_FragColor;\n"
|
||||
"void main() {\n"
|
||||
" float f_add = 34.0;\n"
|
||||
" float f_sub = 30.0;\n"
|
||||
" float f_mul = 64.0;\n"
|
||||
" float f_div = 16.0;\n"
|
||||
" float mixed = 19.0;\n"
|
||||
" int i_add = 34;\n"
|
||||
" int i_sub = 30;\n"
|
||||
" int i_mul = 64;\n"
|
||||
" int i_div = 16;\n"
|
||||
" int i_or = 14;\n"
|
||||
" int i_and = 6;\n"
|
||||
" int i_xor = 5;\n"
|
||||
" int i_shl = 16;\n"
|
||||
" int i_shr = 32;\n"
|
||||
" bool gt_it = true;\n"
|
||||
" bool gt_if = false;\n"
|
||||
" bool gt_ft = true;\n"
|
||||
" bool gt_ff = false;\n"
|
||||
" bool gte_it = true;\n"
|
||||
" bool gte_if = false;\n"
|
||||
" bool gte_ft = true;\n"
|
||||
" bool gte_ff = false;\n"
|
||||
" bool lte_it = true;\n"
|
||||
" bool lte_if = false;\n"
|
||||
" bool lte_ft = true;\n"
|
||||
" bool lte_ff = false;\n"
|
||||
" bool or_t = true;\n"
|
||||
" bool or_f = false;\n"
|
||||
" bool and_t = true;\n"
|
||||
" bool and_f = false;\n"
|
||||
" bool xor_t = true;\n"
|
||||
" bool xor_f = false;\n"
|
||||
" int ternary = 10;\n"
|
||||
" sk_FragColor.x = 34.0;\n"
|
||||
" sk_FragColor.x = 30.0;\n"
|
||||
" sk_FragColor.x = 64.0;\n"
|
||||
" sk_FragColor.x = 16.0;\n"
|
||||
" sk_FragColor.x = 19.0;\n"
|
||||
" sk_FragColor.x = 34.0;\n"
|
||||
" sk_FragColor.x = 30.0;\n"
|
||||
" sk_FragColor.x = 64.0;\n"
|
||||
" sk_FragColor.x = 16.0;\n"
|
||||
" sk_FragColor.x = 14.0;\n"
|
||||
" sk_FragColor.x = 6.0;\n"
|
||||
" sk_FragColor.x = 5.0;\n"
|
||||
" sk_FragColor.x = 16.0;\n"
|
||||
" sk_FragColor.x = 32.0;\n"
|
||||
" sk_FragColor.x = 1.0;\n"
|
||||
" sk_FragColor.x = 0.0;\n"
|
||||
" sk_FragColor.x = 1.0;\n"
|
||||
" sk_FragColor.x = 0.0;\n"
|
||||
" sk_FragColor.x = 1.0;\n"
|
||||
" sk_FragColor.x = 0.0;\n"
|
||||
" sk_FragColor.x = 1.0;\n"
|
||||
" sk_FragColor.x = 0.0;\n"
|
||||
" sk_FragColor.x = 1.0;\n"
|
||||
" sk_FragColor.x = 0.0;\n"
|
||||
" sk_FragColor.x = 1.0;\n"
|
||||
" sk_FragColor.x = 0.0;\n"
|
||||
" sk_FragColor.x = 1.0;\n"
|
||||
" sk_FragColor.x = 0.0;\n"
|
||||
" sk_FragColor.x = 1.0;\n"
|
||||
" sk_FragColor.x = 0.0;\n"
|
||||
" sk_FragColor.x = 1.0;\n"
|
||||
" sk_FragColor.x = 0.0;\n"
|
||||
" sk_FragColor.x = 10.0;\n"
|
||||
" sk_FragColor.x = 0.5;\n"
|
||||
" sk_FragColor = vec4(6.0, 7.0, 9.0, 11.0);\n"
|
||||
" sk_FragColor = vec4(7.0, 9.0, 9.0, 9.0);\n"
|
||||
" sk_FragColor = vec4(2.0, 4.0, 6.0, 8.0);\n"
|
||||
" sk_FragColor = vec4(12.0, 6.0, 4.0, 3.0);\n"
|
||||
" sk_FragColor.x = 6.0;\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
@ -549,40 +628,34 @@ DEF_TEST(SkSLStaticIf, r) {
|
||||
"if (2 > 1) x = 2; else x = 3;"
|
||||
"if (1 > 2) x = 4; else x = 5;"
|
||||
"if (false) x = 6;"
|
||||
"sk_FragColor.r = x;"
|
||||
"}",
|
||||
*SkSL::ShaderCapsFactory::Default(),
|
||||
"#version 400\n"
|
||||
"out vec4 sk_FragColor;\n"
|
||||
"void main() {\n"
|
||||
" int x;\n"
|
||||
" x = 1;\n"
|
||||
" x = 2;\n"
|
||||
" x = 5;\n"
|
||||
" {\n"
|
||||
" }\n"
|
||||
" sk_FragColor.x = 5.0;\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
DEF_TEST(SkSLCaps, r) {
|
||||
test(r,
|
||||
"void main() {"
|
||||
"int x;"
|
||||
"int x = 0;"
|
||||
"int y = 0;"
|
||||
"int z = 0;"
|
||||
"int w = 0;"
|
||||
"if (sk_Caps.externalTextureSupport) x = 1;"
|
||||
"if (sk_Caps.fbFetchSupport) x = 2;"
|
||||
"if (sk_Caps.dropsTileOnZeroDivide && sk_Caps.texelFetchSupport) x = 3;"
|
||||
"if (sk_Caps.dropsTileOnZeroDivide && sk_Caps.canUseAnyFunctionInShader) x = 4;"
|
||||
"if (sk_Caps.fbFetchSupport) y = 1;"
|
||||
"if (sk_Caps.dropsTileOnZeroDivide && sk_Caps.texelFetchSupport) z = 1;"
|
||||
"if (sk_Caps.dropsTileOnZeroDivide && sk_Caps.canUseAnyFunctionInShader) w = 1;"
|
||||
"sk_FragColor = vec4(x, y, z, w);"
|
||||
"}",
|
||||
*SkSL::ShaderCapsFactory::VariousCaps(),
|
||||
"#version 400\n"
|
||||
"out vec4 sk_FragColor;\n"
|
||||
"void main() {\n"
|
||||
" int x;\n"
|
||||
" x = 1;\n"
|
||||
" {\n"
|
||||
" }\n"
|
||||
" x = 3;\n"
|
||||
" {\n"
|
||||
" }\n"
|
||||
" sk_FragColor = vec4(1.0, 0.0, 1.0, 0.0);\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
@ -595,6 +668,7 @@ DEF_TEST(SkSLTexture, r) {
|
||||
"vec4 b = texture(two, vec2(0));"
|
||||
"vec4 c = texture(one, vec2(0));"
|
||||
"vec4 d = texture(two, vec3(0));"
|
||||
"sk_FragColor = vec4(a.x, b.x, c.x, d.x);"
|
||||
"}",
|
||||
*SkSL::ShaderCapsFactory::Default(),
|
||||
"#version 400\n"
|
||||
@ -606,6 +680,7 @@ DEF_TEST(SkSLTexture, r) {
|
||||
" vec4 b = texture(two, vec2(0.0));\n"
|
||||
" vec4 c = textureProj(one, vec2(0.0));\n"
|
||||
" vec4 d = textureProj(two, vec3(0.0));\n"
|
||||
" sk_FragColor = vec4(a.x, b.x, c.x, d.x);\n"
|
||||
"}\n");
|
||||
test(r,
|
||||
"uniform sampler1D one;"
|
||||
@ -615,6 +690,7 @@ DEF_TEST(SkSLTexture, r) {
|
||||
"vec4 b = texture(two, vec2(0));"
|
||||
"vec4 c = texture(one, vec2(0));"
|
||||
"vec4 d = texture(two, vec3(0));"
|
||||
"sk_FragColor = vec4(a.x, b.x, c.x, d.x);"
|
||||
"}",
|
||||
*SkSL::ShaderCapsFactory::Version110(),
|
||||
"#version 110\n"
|
||||
@ -625,6 +701,7 @@ DEF_TEST(SkSLTexture, r) {
|
||||
" vec4 b = texture2D(two, vec2(0.0));\n"
|
||||
" vec4 c = texture1DProj(one, vec2(0.0));\n"
|
||||
" vec4 d = texture2DProj(two, vec3(0.0));\n"
|
||||
" gl_FragColor = vec4(a.x, b.x, c.x, d.x);\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
@ -740,13 +817,14 @@ DEF_TEST(SkSLClipDistance, r) {
|
||||
DEF_TEST(SkSLArrayTypes, r) {
|
||||
test(r,
|
||||
"void main() { vec2 x[2] = vec2[2](vec2(1), vec2(2));"
|
||||
"vec2[2] y = vec2[2](vec2(3), vec2(4)); }",
|
||||
"vec2[2] y = vec2[2](vec2(3), vec2(4));"
|
||||
"sk_FragColor = vec4(x[0], y[1]); }",
|
||||
*SkSL::ShaderCapsFactory::Default(),
|
||||
"#version 400\n"
|
||||
"out vec4 sk_FragColor;\n"
|
||||
"void main() {\n"
|
||||
" vec2 x[2] = vec2[2](vec2(1.0), vec2(2.0));\n"
|
||||
" vec2[2] y = vec2[2](vec2(3.0), vec2(4.0));\n"
|
||||
" sk_FragColor = vec4(vec2[2](vec2(1.0), vec2(2.0))[0], "
|
||||
"vec2[2](vec2(3.0), vec2(4.0))[1]);\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
@ -827,14 +905,13 @@ DEF_TEST(SkSLSwitch, r) {
|
||||
"#version 400\n"
|
||||
"out vec4 sk_FragColor;\n"
|
||||
"void main() {\n"
|
||||
" float x;\n"
|
||||
" switch (2) {\n"
|
||||
" case 0:\n"
|
||||
" x = 0.0;\n"
|
||||
" ;\n"
|
||||
" case 1:\n"
|
||||
" x = 1.0;\n"
|
||||
" ;\n"
|
||||
" default:\n"
|
||||
" x = 2.0;\n"
|
||||
" ;\n"
|
||||
" }\n"
|
||||
" sk_FragColor = vec4(2.0);\n"
|
||||
"}\n");
|
||||
@ -903,4 +980,26 @@ DEF_TEST(SkSLRectangleTexture, r) {
|
||||
"}\n");
|
||||
}
|
||||
|
||||
DEF_TEST(SkSLUnusedVars, r) {
|
||||
test(r,
|
||||
"void main() {"
|
||||
"float a = 1, b = 2, c = 3;"
|
||||
"float d = c;"
|
||||
"float e = d;"
|
||||
"b++;"
|
||||
"d++;"
|
||||
"sk_FragColor = vec4(b, b, d, d);"
|
||||
"}",
|
||||
*SkSL::ShaderCapsFactory::Default(),
|
||||
"#version 400\n"
|
||||
"out vec4 sk_FragColor;\n"
|
||||
"void main() {\n"
|
||||
" float b = 2.0;\n"
|
||||
" float d = 3.0;\n"
|
||||
" b++;\n"
|
||||
" d++;\n"
|
||||
" sk_FragColor = vec4(b, b, d, d);\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user