SkSL function inlining
This first pass adds "one size fits all" function inlining, without any allowances for simple functions that don't need all of this machinery in place. Followup CLs will simplify common cases by e.g. not storing arguments in variables if they're already variables and not wrapping the function body in a loop when it isn't necessary. Change-Id: I4fd8c1655ff48b9e4708bcca03a506df34ceadd9 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/290127 Reviewed-by: Brian Osman <brianosman@google.com> Commit-Queue: Ethan Nicholas <ethannicholas@google.com>
This commit is contained in:
parent
55b3dc0c14
commit
b65024b5f2
@ -39,9 +39,13 @@ public:
|
||||
vVar = args.fUniformHandler->addUniform(&_outer, kFragment_GrShaderFlag, kHalf4_GrSLType,
|
||||
"v");
|
||||
fragBuilder->codeAppendf(
|
||||
"half4 inputColor = %s;\n@if (%s) {\n inputColor = unpremul(inputColor);\n}\n%s "
|
||||
"= %s * inputColor + %s;\n@if (%s) {\n %s = clamp(%s, 0.0, 1.0);\n} else {\n "
|
||||
"%s.w = clamp(%s.w, 0.0, 1.0);\n}\n@if (%s) {\n %s.xyz *= %s.w;\n}\n",
|
||||
"half4 inputColor = %s;\n@if (%s) {\n half4 inlineResult530;\n half4 "
|
||||
"inlineArg530_0 = inputColor;\n do {\n {\n inlineResult530 = "
|
||||
"half4(inlineArg530_0.xyz / max(inlineArg530_0.w, 9.9999997473787516e-05), "
|
||||
"inlineArg530_0.w);\n break;\n }\n } while (false);\n "
|
||||
"inputColor = inlineResult530;\n\n}\n%s = %s * inputColor + %s;\n@if (%s) {\n "
|
||||
"%s = clamp(%s, 0.0, 1.0);\n} else {\n %s.w = clamp(%s.w, 0.0, 1.0);\n}\n@if "
|
||||
"(%s) {\n %s.xyz *= %s.w;\n}\n",
|
||||
args.fInputColor, (_outer.unpremulInput ? "true" : "false"), args.fOutputColor,
|
||||
args.fUniformHandler->getUniformCStr(mVar),
|
||||
args.fUniformHandler->getUniformCStr(vVar),
|
||||
|
@ -34,7 +34,7 @@ String ASTNode::description() const {
|
||||
return "break";
|
||||
case Kind::kCall: {
|
||||
auto iter = this->begin();
|
||||
String result = iter->description();
|
||||
String result = (iter++)->description();
|
||||
result += "(";
|
||||
const char* separator = "";
|
||||
while (iter != this->end()) {
|
||||
@ -230,6 +230,11 @@ String ASTNode::description() const {
|
||||
}
|
||||
return result;
|
||||
}
|
||||
case Kind::kWhile: {
|
||||
return "while (" + this->begin()->description() + ") " +
|
||||
(this->begin() + 1)->description();
|
||||
|
||||
}
|
||||
default:
|
||||
SkASSERT(false);
|
||||
return "<error>";
|
||||
|
@ -1269,6 +1269,14 @@ void Compiler::scanCFG(FunctionDefinition& f) {
|
||||
break;
|
||||
case BasicBlock::Node::kExpression_Kind:
|
||||
offset = (*cfg.fBlocks[i].fNodes[0].expression())->fOffset;
|
||||
if ((*cfg.fBlocks[i].fNodes[0].expression())->fKind ==
|
||||
Expression::kBoolLiteral_Kind) {
|
||||
// Function inlining can generate do { ... } while(false) loops which always
|
||||
// break, so the boolean condition is considered unreachable. Since not
|
||||
// being able to reach a literal is a non-issue in the first place, we
|
||||
// don't report an error in this case.
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
this->error(offset, String("unreachable"));
|
||||
|
@ -400,6 +400,11 @@ private:
|
||||
return "<defined>";
|
||||
}
|
||||
|
||||
int nodeCount() const override {
|
||||
SkASSERT(false);
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::unique_ptr<Expression> clone() const override {
|
||||
return std::unique_ptr<Expression>(new Defined(fType));
|
||||
}
|
||||
|
@ -1521,11 +1521,15 @@ void GLSLCodeGenerator::writeStatements(const std::vector<std::unique_ptr<Statem
|
||||
}
|
||||
|
||||
void GLSLCodeGenerator::writeBlock(const Block& b) {
|
||||
this->writeLine("{");
|
||||
fIndentation++;
|
||||
if (b.fIsScope) {
|
||||
this->writeLine("{");
|
||||
fIndentation++;
|
||||
}
|
||||
this->writeStatements(b.fStatements);
|
||||
fIndentation--;
|
||||
this->write("}");
|
||||
if (b.fIsScope) {
|
||||
fIndentation--;
|
||||
this->write("}");
|
||||
}
|
||||
}
|
||||
|
||||
void GLSLCodeGenerator::writeIfStatement(const IfStatement& stmt) {
|
||||
|
@ -182,7 +182,7 @@ void IRGenerator::finish() {
|
||||
fSettings = nullptr;
|
||||
}
|
||||
|
||||
std::unique_ptr<Statement> IRGenerator::convertStatement(const ASTNode& statement) {
|
||||
std::unique_ptr<Statement> IRGenerator::convertSingleStatement(const ASTNode& statement) {
|
||||
switch (statement.fKind) {
|
||||
case ASTNode::Kind::kBlock:
|
||||
return this->convertBlock(statement);
|
||||
@ -228,6 +228,24 @@ std::unique_ptr<Statement> IRGenerator::convertStatement(const ASTNode& statemen
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<Statement> IRGenerator::convertStatement(const ASTNode& statement) {
|
||||
std::vector<std::unique_ptr<Statement>> oldExtraStatements = std::move(fExtraStatements);
|
||||
std::unique_ptr<Statement> result = this->convertSingleStatement(statement);
|
||||
if (!result) {
|
||||
fExtraStatements = std::move(oldExtraStatements);
|
||||
return nullptr;
|
||||
}
|
||||
if (fExtraStatements.size()) {
|
||||
fExtraStatements.push_back(std::move(result));
|
||||
std::unique_ptr<Statement> block(new Block(-1, std::move(fExtraStatements), nullptr,
|
||||
false));
|
||||
fExtraStatements = std::move(oldExtraStatements);
|
||||
return block;
|
||||
}
|
||||
fExtraStatements = std::move(oldExtraStatements);
|
||||
return result;
|
||||
}
|
||||
|
||||
std::unique_ptr<Block> IRGenerator::convertBlock(const ASTNode& block) {
|
||||
SkASSERT(block.fKind == ASTNode::Kind::kBlock);
|
||||
AutoSymbolTable table(this);
|
||||
@ -496,15 +514,22 @@ std::unique_ptr<Statement> IRGenerator::convertFor(const ASTNode& f) {
|
||||
++iter;
|
||||
std::unique_ptr<Expression> test;
|
||||
if (*iter) {
|
||||
bool oldCanInline = fCanInline;
|
||||
fCanInline = false;
|
||||
test = this->coerce(this->convertExpression(*iter), *fContext.fBool_Type);
|
||||
fCanInline = oldCanInline;
|
||||
if (!test) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
}
|
||||
++iter;
|
||||
std::unique_ptr<Expression> next;
|
||||
if (*iter) {
|
||||
bool oldCanInline = fCanInline;
|
||||
fCanInline = false;
|
||||
next = this->convertExpression(*iter);
|
||||
fCanInline = oldCanInline;
|
||||
if (!next) {
|
||||
return nullptr;
|
||||
}
|
||||
@ -524,8 +549,11 @@ std::unique_ptr<Statement> IRGenerator::convertWhile(const ASTNode& w) {
|
||||
SkASSERT(w.fKind == ASTNode::Kind::kWhile);
|
||||
AutoLoopLevel level(this);
|
||||
auto iter = w.begin();
|
||||
bool oldCanInline = fCanInline;
|
||||
fCanInline = false;
|
||||
std::unique_ptr<Expression> test = this->coerce(this->convertExpression(*(iter++)),
|
||||
*fContext.fBool_Type);
|
||||
fCanInline = oldCanInline;
|
||||
if (!test) {
|
||||
return nullptr;
|
||||
}
|
||||
@ -545,8 +573,11 @@ std::unique_ptr<Statement> IRGenerator::convertDo(const ASTNode& d) {
|
||||
if (!statement) {
|
||||
return nullptr;
|
||||
}
|
||||
bool oldCanInline = fCanInline;
|
||||
fCanInline = false;
|
||||
std::unique_ptr<Expression> test = this->coerce(this->convertExpression(*(iter++)),
|
||||
*fContext.fBool_Type);
|
||||
fCanInline = oldCanInline;
|
||||
if (!test) {
|
||||
return nullptr;
|
||||
}
|
||||
@ -884,7 +915,7 @@ void IRGenerator::convertFunction(const ASTNode& f) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (other->fDefined && !other->fBuiltin) {
|
||||
if (other->fDefinition && !other->fBuiltin) {
|
||||
fErrors.error(f.fOffset, "duplicate definition of " +
|
||||
other->declaration());
|
||||
}
|
||||
@ -907,7 +938,6 @@ void IRGenerator::convertFunction(const ASTNode& f) {
|
||||
// compile body
|
||||
SkASSERT(!fCurrentFunction);
|
||||
fCurrentFunction = decl;
|
||||
decl->fDefined = true;
|
||||
std::shared_ptr<SymbolTable> old = fSymbolTable;
|
||||
AutoSymbolTable table(this);
|
||||
if (fd.fName == "main" && fKind == Program::kPipelineStage_Kind) {
|
||||
@ -940,6 +970,7 @@ void IRGenerator::convertFunction(const ASTNode& f) {
|
||||
}
|
||||
std::unique_ptr<FunctionDefinition> result(new FunctionDefinition(f.fOffset, *decl,
|
||||
std::move(body)));
|
||||
decl->fDefinition = result.get();
|
||||
result->fSource = &f;
|
||||
fProgramElements->push_back(std::move(result));
|
||||
}
|
||||
@ -1715,7 +1746,15 @@ std::unique_ptr<Expression> IRGenerator::convertBinaryExpression(const ASTNode&
|
||||
if (!left) {
|
||||
return nullptr;
|
||||
}
|
||||
Token::Kind op = expression.getToken().fKind;
|
||||
bool oldCanInline = fCanInline;
|
||||
if (op == Token::Kind::TK_LOGICALAND || op == Token::Kind::TK_LOGICALOR) {
|
||||
// can't inline the right side of a short-circuiting boolean, because our inlining
|
||||
// approach runs things out of order
|
||||
fCanInline = false;
|
||||
}
|
||||
std::unique_ptr<Expression> right = this->convertExpression(*(iter++));
|
||||
fCanInline = oldCanInline;
|
||||
if (!right) {
|
||||
return nullptr;
|
||||
}
|
||||
@ -1734,7 +1773,6 @@ std::unique_ptr<Expression> IRGenerator::convertBinaryExpression(const ASTNode&
|
||||
} else {
|
||||
rawRightType = &right->fType;
|
||||
}
|
||||
Token::Kind op = expression.getToken().fKind;
|
||||
if (!determine_binary_type(fContext, op, *rawLeftType, *rawRightType, &leftType, &rightType,
|
||||
&resultType, !Compiler::IsAssignment(op))) {
|
||||
fErrors.error(expression.fOffset, String("type mismatch: '") +
|
||||
@ -1811,6 +1849,324 @@ std::unique_ptr<Expression> IRGenerator::convertTernaryExpression(const ASTNode&
|
||||
std::move(ifFalse)));
|
||||
}
|
||||
|
||||
std::unique_ptr<Expression> IRGenerator::inlineExpression(int offset,
|
||||
std::map<const Variable*,
|
||||
const Variable*>* varMap,
|
||||
const Expression& expression) {
|
||||
auto expr = [&](const std::unique_ptr<Expression>& e) {
|
||||
if (e) {
|
||||
return this->inlineExpression(offset, varMap, *e);
|
||||
}
|
||||
return std::unique_ptr<Expression>(nullptr);
|
||||
};
|
||||
switch (expression.fKind) {
|
||||
case Expression::kBinary_Kind: {
|
||||
const BinaryExpression& b = (const BinaryExpression&) expression;
|
||||
return std::unique_ptr<Expression>(new BinaryExpression(offset,
|
||||
expr(b.fLeft),
|
||||
b.fOperator,
|
||||
expr(b.fRight),
|
||||
b.fType));
|
||||
}
|
||||
case Expression::kBoolLiteral_Kind:
|
||||
case Expression::kIntLiteral_Kind:
|
||||
case Expression::kFloatLiteral_Kind:
|
||||
case Expression::kNullLiteral_Kind:
|
||||
return expression.clone();
|
||||
case Expression::kConstructor_Kind: {
|
||||
const Constructor& c = (const Constructor&) expression;
|
||||
std::vector<std::unique_ptr<Expression>> args;
|
||||
for (const auto& arg : c.fArguments) {
|
||||
args.push_back(expr(arg));
|
||||
}
|
||||
return std::unique_ptr<Expression>(new Constructor(offset, c.fType, std::move(args)));
|
||||
}
|
||||
case Expression::kExternalFunctionCall_Kind: {
|
||||
const ExternalFunctionCall& e = (const ExternalFunctionCall&) expression;
|
||||
std::vector<std::unique_ptr<Expression>> args;
|
||||
for (const auto& arg : e.fArguments) {
|
||||
args.push_back(expr(arg));
|
||||
}
|
||||
return std::unique_ptr<Expression>(new ExternalFunctionCall(offset, e.fType,
|
||||
e.fFunction,
|
||||
std::move(args)));
|
||||
}
|
||||
case Expression::kExternalValue_Kind:
|
||||
return expression.clone();
|
||||
case Expression::kFieldAccess_Kind: {
|
||||
const FieldAccess& f = (const FieldAccess&) expression;
|
||||
return std::unique_ptr<Expression>(new FieldAccess(expr(f.fBase), f.fFieldIndex,
|
||||
f.fOwnerKind));
|
||||
}
|
||||
case Expression::kFunctionCall_Kind: {
|
||||
const FunctionCall& c = (const FunctionCall&) expression;
|
||||
std::vector<std::unique_ptr<Expression>> args;
|
||||
for (const auto& arg : c.fArguments) {
|
||||
args.push_back(expr(arg));
|
||||
}
|
||||
return std::unique_ptr<Expression>(new FunctionCall(offset, c.fType, c.fFunction,
|
||||
std::move(args)));
|
||||
}
|
||||
case Expression::kIndex_Kind: {
|
||||
const IndexExpression& idx = (const IndexExpression&) expression;
|
||||
return std::unique_ptr<Expression>(new IndexExpression(fContext, expr(idx.fBase),
|
||||
expr(idx.fIndex)));
|
||||
}
|
||||
case Expression::kPrefix_Kind: {
|
||||
const PrefixExpression& p = (const PrefixExpression&) expression;
|
||||
return std::unique_ptr<Expression>(new PrefixExpression(p.fOperator, expr(p.fOperand)));
|
||||
}
|
||||
case Expression::kPostfix_Kind: {
|
||||
const PostfixExpression& p = (const PostfixExpression&) expression;
|
||||
return std::unique_ptr<Expression>(new PostfixExpression(expr(p.fOperand),
|
||||
p.fOperator));
|
||||
}
|
||||
case Expression::kSetting_Kind:
|
||||
return expression.clone();
|
||||
case Expression::kSwizzle_Kind: {
|
||||
const Swizzle& s = (const Swizzle&) expression;
|
||||
return std::unique_ptr<Expression>(new Swizzle(fContext, expr(s.fBase), s.fComponents));
|
||||
}
|
||||
case Expression::kTernary_Kind: {
|
||||
const TernaryExpression& t = (const TernaryExpression&) expression;
|
||||
return std::unique_ptr<Expression>(new TernaryExpression(offset, expr(t.fTest),
|
||||
expr(t.fIfTrue),
|
||||
expr(t.fIfFalse)));
|
||||
}
|
||||
case Expression::kVariableReference_Kind: {
|
||||
const VariableReference& v = (const VariableReference&) expression;
|
||||
auto found = varMap->find(&v.fVariable);
|
||||
if (found != varMap->end()) {
|
||||
return std::unique_ptr<Expression>(new VariableReference(offset,
|
||||
*found->second,
|
||||
v.fRefKind));
|
||||
}
|
||||
return v.clone();
|
||||
}
|
||||
default:
|
||||
SkASSERT(false);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<Statement> IRGenerator::inlineStatement(int offset,
|
||||
std::map<const Variable*,
|
||||
const Variable*>* varMap,
|
||||
const Variable* returnVar,
|
||||
const Statement& statement) {
|
||||
auto stmt = [&](const std::unique_ptr<Statement>& s) {
|
||||
if (s) {
|
||||
return this->inlineStatement(offset, varMap, returnVar, *s);
|
||||
}
|
||||
return std::unique_ptr<Statement>(nullptr);
|
||||
};
|
||||
auto stmts = [&](const std::vector<std::unique_ptr<Statement>>& ss) {
|
||||
std::vector<std::unique_ptr<Statement>> result;
|
||||
for (const auto& s : ss) {
|
||||
result.push_back(stmt(s));
|
||||
}
|
||||
return result;
|
||||
};
|
||||
auto expr = [&](const std::unique_ptr<Expression>& e) {
|
||||
if (e) {
|
||||
return this->inlineExpression(offset, varMap, *e);
|
||||
}
|
||||
return std::unique_ptr<Expression>(nullptr);
|
||||
};
|
||||
switch (statement.fKind) {
|
||||
case Statement::kBlock_Kind: {
|
||||
const Block& b = (const Block&) statement;
|
||||
return std::unique_ptr<Statement>(new Block(offset, stmts(b.fStatements), b.fSymbols,
|
||||
b.fIsScope));
|
||||
}
|
||||
|
||||
case Statement::kBreak_Kind:
|
||||
case Statement::kContinue_Kind:
|
||||
case Statement::kDiscard_Kind:
|
||||
return statement.clone();
|
||||
|
||||
case Statement::kDo_Kind: {
|
||||
const DoStatement& d = (const DoStatement&) statement;
|
||||
return std::unique_ptr<Statement>(new DoStatement(offset,
|
||||
stmt(d.fStatement),
|
||||
expr(d.fTest)));
|
||||
}
|
||||
case Statement::kExpression_Kind: {
|
||||
const ExpressionStatement& e = (const ExpressionStatement&) statement;
|
||||
return std::unique_ptr<Statement>(new ExpressionStatement(expr(e.fExpression)));
|
||||
}
|
||||
case Statement::kFor_Kind: {
|
||||
const ForStatement& f = (const ForStatement&) statement;
|
||||
// need to ensure initializer is evaluated first so that we've already remapped its
|
||||
// declarations by the time we evaluate test & next
|
||||
std::unique_ptr<Statement> initializer = stmt(f.fInitializer);
|
||||
return std::unique_ptr<Statement>(new ForStatement(offset, std::move(initializer),
|
||||
expr(f.fTest), expr(f.fNext),
|
||||
stmt(f.fStatement), f.fSymbols));
|
||||
}
|
||||
case Statement::kIf_Kind: {
|
||||
const IfStatement& i = (const IfStatement&) statement;
|
||||
return std::unique_ptr<Statement>(new IfStatement(offset, i.fIsStatic, expr(i.fTest),
|
||||
stmt(i.fIfTrue), stmt(i.fIfFalse)));
|
||||
}
|
||||
case Statement::kNop_Kind:
|
||||
return statement.clone();
|
||||
case Statement::kReturn_Kind: {
|
||||
const ReturnStatement& r = (const ReturnStatement&) statement;
|
||||
if (r.fExpression) {
|
||||
std::vector<std::unique_ptr<Statement>> block;
|
||||
block.emplace_back(new ExpressionStatement(
|
||||
std::unique_ptr<Expression>(new BinaryExpression(offset,
|
||||
std::unique_ptr<Expression>(new VariableReference(
|
||||
offset,
|
||||
*returnVar,
|
||||
VariableReference::kWrite_RefKind)),
|
||||
Token::Kind::TK_EQ,
|
||||
expr(r.fExpression),
|
||||
returnVar->fType))));
|
||||
block.emplace_back(new BreakStatement(offset));
|
||||
return std::unique_ptr<Statement>(new Block(offset, std::move(block)));
|
||||
} else {
|
||||
return std::unique_ptr<Statement>(new BreakStatement(offset));
|
||||
}
|
||||
}
|
||||
case Statement::kSwitch_Kind: {
|
||||
const SwitchStatement& ss = (const SwitchStatement&) statement;
|
||||
std::vector<std::unique_ptr<SwitchCase>> cases;
|
||||
for (const auto& sc : ss.fCases) {
|
||||
cases.emplace_back(new SwitchCase(offset, expr(sc->fValue),
|
||||
stmts(sc->fStatements)));
|
||||
}
|
||||
return std::unique_ptr<Statement>(new SwitchStatement(offset, ss.fIsStatic,
|
||||
expr(ss.fValue),
|
||||
std::move(cases),
|
||||
ss.fSymbols));
|
||||
}
|
||||
case Statement::kVarDeclaration_Kind: {
|
||||
const VarDeclaration& decl = (const VarDeclaration&) statement;
|
||||
std::vector<std::unique_ptr<Expression>> sizes;
|
||||
for (const auto& size : decl.fSizes) {
|
||||
sizes.push_back(expr(size));
|
||||
}
|
||||
std::unique_ptr<Expression> initialValue = expr(decl.fValue);
|
||||
const Variable* old = decl.fVar;
|
||||
Variable* clone = (Variable*) fSymbolTable->takeOwnership(std::unique_ptr<Symbol>(
|
||||
new Variable(offset, old->fModifiers, old->fName,
|
||||
old->fType, old->fStorage,
|
||||
initialValue.get())));
|
||||
(*varMap)[old] = clone;
|
||||
return std::unique_ptr<Statement>(new VarDeclaration(clone, std::move(sizes),
|
||||
std::move(initialValue)));
|
||||
}
|
||||
case Statement::kVarDeclarations_Kind: {
|
||||
const VarDeclarations& decls = *((VarDeclarationsStatement&) statement).fDeclaration;
|
||||
std::vector<std::unique_ptr<VarDeclaration>> vars;
|
||||
for (const auto& var : decls.fVars) {
|
||||
vars.emplace_back((VarDeclaration*) stmt(var).release());
|
||||
}
|
||||
return std::unique_ptr<Statement>(new VarDeclarationsStatement(
|
||||
std::unique_ptr<VarDeclarations>(new VarDeclarations(offset, &decls.fBaseType,
|
||||
std::move(vars)))));
|
||||
}
|
||||
case Statement::kWhile_Kind: {
|
||||
const WhileStatement& w = (const WhileStatement&) statement;
|
||||
return std::unique_ptr<Statement>(new WhileStatement(offset,
|
||||
expr(w.fTest),
|
||||
stmt(w.fStatement)));
|
||||
}
|
||||
default:
|
||||
SkASSERT(false);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<Expression> IRGenerator::inlineCall(
|
||||
int offset,
|
||||
const FunctionDefinition& function,
|
||||
std::vector<std::unique_ptr<Expression>> arguments) {
|
||||
// Inlining is more complicated here than in a typical compiler, because we have to have a
|
||||
// high-level IR and can't just drop statements into the middle of an expression or even use
|
||||
// gotos.
|
||||
//
|
||||
// Since we can't insert statements into an expression, we run the inline function as extra
|
||||
// statements before the statement we're currently processing, relying on a lack of execution
|
||||
// order guarantees. Since we can't use gotos (which are normally used to replace return
|
||||
// statements), we wrap the whole function in a loop and use break statements to jump to the
|
||||
// end.
|
||||
std::vector<std::unique_ptr<Statement>> body;
|
||||
Variable* resultVar;
|
||||
if (function.fDeclaration.fReturnType != *fContext.fVoid_Type) {
|
||||
std::unique_ptr<String> name(new String());
|
||||
name->appendf("inlineResult%d", offset);
|
||||
String* namePtr = (String*) fSymbolTable->takeOwnership(std::move(name));
|
||||
resultVar = (Variable*) fSymbolTable->takeOwnership(std::unique_ptr<Symbol>(
|
||||
new Variable(-1, Modifiers(), namePtr->c_str(),
|
||||
function.fDeclaration.fReturnType,
|
||||
Variable::kLocal_Storage,
|
||||
nullptr)));
|
||||
std::vector<std::unique_ptr<VarDeclaration>> variables;
|
||||
variables.emplace_back(new VarDeclaration(resultVar, {}, nullptr));
|
||||
fExtraStatements.emplace_back(new VarDeclarationsStatement(
|
||||
std::unique_ptr<VarDeclarations>(new VarDeclarations(offset,
|
||||
&resultVar->fType,
|
||||
std::move(variables)))));
|
||||
|
||||
} else {
|
||||
resultVar = nullptr;
|
||||
}
|
||||
std::map<const Variable*, const Variable*> varMap;
|
||||
// create variables to hold the arguments and assign the arguments to them
|
||||
for (int i = 0; i < (int) arguments.size(); ++i) {
|
||||
std::unique_ptr<String> argName(new String());
|
||||
argName->appendf("inlineArg%d_%d", offset, i);
|
||||
String* argNamePtr = (String*) fSymbolTable->takeOwnership(std::move(argName));
|
||||
Variable* argVar = (Variable*) fSymbolTable->takeOwnership(std::unique_ptr<Symbol>(
|
||||
new Variable(-1, Modifiers(),
|
||||
argNamePtr->c_str(),
|
||||
arguments[i]->fType,
|
||||
Variable::kLocal_Storage,
|
||||
arguments[i].get())));
|
||||
varMap[function.fDeclaration.fParameters[i]] = argVar;
|
||||
std::vector<std::unique_ptr<VarDeclaration>> vars;
|
||||
if (function.fDeclaration.fParameters[i]->fModifiers.fFlags & Modifiers::kOut_Flag) {
|
||||
vars.emplace_back(new VarDeclaration(argVar, {}, arguments[i]->clone()));
|
||||
} else {
|
||||
vars.emplace_back(new VarDeclaration(argVar, {}, std::move(arguments[i])));
|
||||
}
|
||||
fExtraStatements.emplace_back(new VarDeclarationsStatement(
|
||||
std::unique_ptr<VarDeclarations>(new VarDeclarations(offset,
|
||||
&argVar->fType,
|
||||
std::move(vars)))));
|
||||
}
|
||||
for (const auto& s : ((Block&) *function.fBody).fStatements) {
|
||||
body.push_back(this->inlineStatement(offset, &varMap, resultVar, *s));
|
||||
}
|
||||
fExtraStatements.emplace_back(new DoStatement(-1,
|
||||
std::unique_ptr<Statement>(new Block(-1, std::move(body))),
|
||||
std::unique_ptr<Expression>(new BoolLiteral(fContext, -1, false))));
|
||||
// copy the values of out parameters into their destinations
|
||||
for (size_t i = 0; i < arguments.size(); ++i) {
|
||||
const Variable* p = function.fDeclaration.fParameters[i];
|
||||
if (p->fModifiers.fFlags & Modifiers::kOut_Flag) {
|
||||
std::unique_ptr<Expression> varRef(new VariableReference(offset, *varMap[p]));
|
||||
fExtraStatements.emplace_back(new ExpressionStatement(
|
||||
std::unique_ptr<Expression>(new BinaryExpression(offset,
|
||||
arguments[i]->clone(),
|
||||
Token::Kind::TK_EQ,
|
||||
std::move(varRef),
|
||||
arguments[i]->fType))));
|
||||
}
|
||||
}
|
||||
if (function.fDeclaration.fReturnType != *fContext.fVoid_Type) {
|
||||
return std::unique_ptr<Expression>(new VariableReference(-1, *resultVar));
|
||||
} else {
|
||||
// it's a void function, so it doesn't actually result in anything, but we have to return
|
||||
// something non-null as a standin
|
||||
return std::unique_ptr<Expression>(new BoolLiteral(fContext, -1, false));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::unique_ptr<Expression> IRGenerator::call(int offset,
|
||||
const FunctionDeclaration& function,
|
||||
std::vector<std::unique_ptr<Expression>> arguments) {
|
||||
@ -1835,7 +2191,7 @@ std::unique_ptr<Expression> IRGenerator::call(int offset,
|
||||
fErrors.error(offset, msg);
|
||||
return nullptr;
|
||||
}
|
||||
if (fKind == Program::kPipelineStage_Kind && !function.fDefined && !function.fBuiltin) {
|
||||
if (fKind == Program::kPipelineStage_Kind && !function.fDefinition && !function.fBuiltin) {
|
||||
String msg = "call to undefined function '" + function.fName + "'";
|
||||
fErrors.error(offset, msg);
|
||||
return nullptr;
|
||||
@ -1866,6 +2222,9 @@ std::unique_ptr<Expression> IRGenerator::call(int offset,
|
||||
VariableReference::kPointer_RefKind);
|
||||
}
|
||||
}
|
||||
if (fCanInline && function.fDefinition && function.fDefinition->canBeInlined()) {
|
||||
return this->inlineCall(offset, *function.fDefinition, std::move(arguments));
|
||||
}
|
||||
return std::unique_ptr<FunctionCall>(new FunctionCall(offset, *returnType, function,
|
||||
std::move(arguments)));
|
||||
}
|
||||
|
@ -83,11 +83,21 @@ private:
|
||||
std::unique_ptr<VarDeclarations> convertVarDeclarations(const ASTNode& decl,
|
||||
Variable::Storage storage);
|
||||
void convertFunction(const ASTNode& f);
|
||||
std::unique_ptr<Statement> convertSingleStatement(const ASTNode& statement);
|
||||
std::unique_ptr<Statement> convertStatement(const ASTNode& statement);
|
||||
std::unique_ptr<Expression> convertExpression(const ASTNode& expression);
|
||||
std::unique_ptr<ModifiersDeclaration> convertModifiersDeclaration(const ASTNode& m);
|
||||
|
||||
const Type* convertType(const ASTNode& type);
|
||||
std::unique_ptr<Expression> inlineExpression(int offset,
|
||||
std::map<const Variable*, const Variable*>* varMap,
|
||||
const Expression& expression);
|
||||
std::unique_ptr<Statement> inlineStatement(int offset,
|
||||
std::map<const Variable*, const Variable*>* varMap,
|
||||
const Variable* returnVar,
|
||||
const Statement& statement);
|
||||
std::unique_ptr<Expression> inlineCall(int offset, const FunctionDefinition& function,
|
||||
std::vector<std::unique_ptr<Expression>> arguments);
|
||||
std::unique_ptr<Expression> call(int offset,
|
||||
const FunctionDeclaration& function,
|
||||
std::vector<std::unique_ptr<Expression>> arguments);
|
||||
@ -156,6 +166,9 @@ private:
|
||||
std::unordered_map<String, Program::Settings::Value> fCapsMap;
|
||||
std::shared_ptr<SymbolTable> fRootSymbolTable;
|
||||
std::shared_ptr<SymbolTable> fSymbolTable;
|
||||
// additional statements that need to be inserted before the one that convertStatement is
|
||||
// currently working on
|
||||
std::vector<std::unique_ptr<Statement>> fExtraStatements;
|
||||
// Symbols which have definitions in the include files. The bool tells us whether this
|
||||
// intrinsic has been included already.
|
||||
std::map<String, std::pair<std::unique_ptr<ProgramElement>, bool>>* fIntrinsics = nullptr;
|
||||
@ -168,6 +181,7 @@ private:
|
||||
Variable* fRTAdjust;
|
||||
Variable* fRTAdjustInterfaceBlock;
|
||||
int fRTAdjustFieldIndex;
|
||||
bool fCanInline = true;
|
||||
|
||||
friend class AutoSymbolTable;
|
||||
friend class AutoLoopLevel;
|
||||
|
@ -1164,11 +1164,15 @@ void MetalCodeGenerator::writeStatements(const std::vector<std::unique_ptr<State
|
||||
}
|
||||
|
||||
void MetalCodeGenerator::writeBlock(const Block& b) {
|
||||
this->writeLine("{");
|
||||
fIndentation++;
|
||||
if (b.fIsScope) {
|
||||
this->writeLine("{");
|
||||
fIndentation++;
|
||||
}
|
||||
this->writeStatements(b.fStatements);
|
||||
fIndentation--;
|
||||
this->write("}");
|
||||
if (b.fIsScope) {
|
||||
fIndentation--;
|
||||
this->write("}");
|
||||
}
|
||||
}
|
||||
|
||||
void MetalCodeGenerator::writeIfStatement(const IfStatement& stmt) {
|
||||
|
@ -2987,14 +2987,6 @@ void SPIRVCodeGenerator::writeWhileStatement(const WhileStatement& w, OutputStre
|
||||
}
|
||||
|
||||
void SPIRVCodeGenerator::writeDoStatement(const DoStatement& d, OutputStream& out) {
|
||||
// We believe the do loop code below will work, but Skia doesn't actually use them and
|
||||
// adequately testing this code in the absence of Skia exercising it isn't straightforward. For
|
||||
// the time being, we just fail with an error due to the lack of testing. If you encounter this
|
||||
// message, simply remove the error call below to see whether our do loop support actually
|
||||
// works.
|
||||
fErrors.error(d.fOffset, "internal error: do loop support has been disabled in SPIR-V, see "
|
||||
"SkSLSPIRVCodeGenerator.cpp for details");
|
||||
|
||||
SpvId header = this->nextId();
|
||||
SpvId start = this->nextId();
|
||||
SpvId next = this->nextId();
|
||||
|
@ -199,9 +199,9 @@ bool SectionAndParameterHelper::hasCoordOverrides(const Statement& s, const Vari
|
||||
}
|
||||
case Statement::kFor_Kind: {
|
||||
const ForStatement& f = (const ForStatement&) s;
|
||||
return this->hasCoordOverrides(*f.fInitializer, fp) ||
|
||||
this->hasCoordOverrides(*f.fTest, fp) ||
|
||||
this->hasCoordOverrides(*f.fNext, fp) ||
|
||||
return (f.fInitializer ? this->hasCoordOverrides(*f.fInitializer, fp) : 0) ||
|
||||
(f.fTest ? this->hasCoordOverrides(*f.fTest, fp) : 0) ||
|
||||
(f.fNext ? this->hasCoordOverrides(*f.fNext, fp) : 0) ||
|
||||
this->hasCoordOverrides(*f.fStatement, fp);
|
||||
}
|
||||
case Statement::kWhile_Kind: {
|
||||
@ -228,7 +228,6 @@ bool SectionAndParameterHelper::hasCoordOverrides(const Statement& s, const Vari
|
||||
case Statement::kBreak_Kind:
|
||||
case Statement::kContinue_Kind:
|
||||
case Statement::kDiscard_Kind:
|
||||
case Statement::kGroup_Kind:
|
||||
case Statement::kNop_Kind:
|
||||
return false;
|
||||
}
|
||||
@ -321,6 +320,13 @@ SampleMatrix SectionAndParameterHelper::getMatrix(const Expression& e, const Var
|
||||
return SampleMatrix();
|
||||
}
|
||||
|
||||
SampleMatrix SectionAndParameterHelper::getMatrix(const Expression* e, const Variable& fp) {
|
||||
if (e) {
|
||||
return this->getMatrix(*e, fp);
|
||||
}
|
||||
return SampleMatrix();
|
||||
}
|
||||
|
||||
SampleMatrix SectionAndParameterHelper::getMatrix(const Statement& s, const Variable& fp) {
|
||||
switch (s.fKind) {
|
||||
case Statement::kBlock_Kind: {
|
||||
@ -361,9 +367,9 @@ SampleMatrix SectionAndParameterHelper::getMatrix(const Statement& s, const Vari
|
||||
}
|
||||
case Statement::kFor_Kind: {
|
||||
const ForStatement& f = (const ForStatement&) s;
|
||||
return this->getMatrix(*f.fInitializer, fp).merge(
|
||||
this->getMatrix(*f.fTest, fp).merge(
|
||||
this->getMatrix(*f.fNext, fp).merge(
|
||||
return this->getMatrix(f.fInitializer.get(), fp).merge(
|
||||
this->getMatrix(f.fTest.get(), fp).merge(
|
||||
this->getMatrix(f.fNext.get(), fp).merge(
|
||||
this->getMatrix(*f.fStatement, fp))));
|
||||
}
|
||||
case Statement::kWhile_Kind: {
|
||||
@ -387,7 +393,6 @@ SampleMatrix SectionAndParameterHelper::getMatrix(const Statement& s, const Vari
|
||||
case Statement::kBreak_Kind:
|
||||
case Statement::kContinue_Kind:
|
||||
case Statement::kDiscard_Kind:
|
||||
case Statement::kGroup_Kind:
|
||||
case Statement::kNop_Kind:
|
||||
return SampleMatrix();
|
||||
}
|
||||
@ -395,4 +400,12 @@ SampleMatrix SectionAndParameterHelper::getMatrix(const Statement& s, const Vari
|
||||
return SampleMatrix();
|
||||
}
|
||||
|
||||
SampleMatrix SectionAndParameterHelper::getMatrix(const Statement* s, const Variable& fp) {
|
||||
if (s) {
|
||||
return this->getMatrix(*s, fp);
|
||||
}
|
||||
return SampleMatrix();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -122,6 +122,10 @@ private:
|
||||
|
||||
SampleMatrix getMatrix(const Expression& e, const Variable& fp);
|
||||
|
||||
SampleMatrix getMatrix(const Statement* s, const Variable& fp);
|
||||
|
||||
SampleMatrix getMatrix(const Expression* e, const Variable& fp);
|
||||
|
||||
SampleMatrix getMatrix(const ProgramElement& p, const Variable& fp);
|
||||
|
||||
const Program& fProgram;
|
||||
|
@ -45,6 +45,10 @@ struct BinaryExpression : public Expression {
|
||||
return fLeft->hasProperty(property) || fRight->hasProperty(property);
|
||||
}
|
||||
|
||||
int nodeCount() const override {
|
||||
return 1 + fLeft->nodeCount() + fRight->nodeCount();
|
||||
}
|
||||
|
||||
std::unique_ptr<Expression> clone() const override {
|
||||
return std::unique_ptr<Expression>(new BinaryExpression(fOffset, fLeft->clone(), fOperator,
|
||||
fRight->clone(), fType));
|
||||
|
@ -18,10 +18,11 @@ namespace SkSL {
|
||||
*/
|
||||
struct Block : public Statement {
|
||||
Block(int offset, std::vector<std::unique_ptr<Statement>> statements,
|
||||
const std::shared_ptr<SymbolTable> symbols = nullptr)
|
||||
const std::shared_ptr<SymbolTable> symbols = nullptr, bool isScope = true)
|
||||
: INHERITED(offset, kBlock_Kind)
|
||||
, fSymbols(std::move(symbols))
|
||||
, fStatements(std::move(statements)) {}
|
||||
, fStatements(std::move(statements))
|
||||
, fIsScope(isScope) {}
|
||||
|
||||
bool isEmpty() const override {
|
||||
for (const auto& s : fStatements) {
|
||||
@ -32,12 +33,21 @@ struct Block : public Statement {
|
||||
return true;
|
||||
}
|
||||
|
||||
int nodeCount() const override {
|
||||
int result = 1;
|
||||
for (const auto& s : fStatements) {
|
||||
result += s->nodeCount();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::unique_ptr<Statement> clone() const override {
|
||||
std::vector<std::unique_ptr<Statement>> cloned;
|
||||
for (const auto& s : fStatements) {
|
||||
cloned.push_back(s->clone());
|
||||
}
|
||||
return std::unique_ptr<Statement>(new Block(fOffset, std::move(cloned), fSymbols));
|
||||
return std::unique_ptr<Statement>(new Block(fOffset, std::move(cloned), fSymbols,
|
||||
fIsScope));
|
||||
}
|
||||
|
||||
String description() const override {
|
||||
@ -54,6 +64,10 @@ struct Block : public Statement {
|
||||
// because destroying statements can modify reference counts in symbols
|
||||
const std::shared_ptr<SymbolTable> fSymbols;
|
||||
std::vector<std::unique_ptr<Statement>> fStatements;
|
||||
// if isScope is false, this is just a group of statements rather than an actual language-level
|
||||
// block. This allows us to pass around multiple statements as if they were a single unit, with
|
||||
// no semantic impact.
|
||||
bool fIsScope;
|
||||
|
||||
typedef Statement INHERITED;
|
||||
};
|
||||
|
@ -38,6 +38,10 @@ struct BoolLiteral : public Expression {
|
||||
return fValue == b.fValue;
|
||||
}
|
||||
|
||||
int nodeCount() const override {
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::unique_ptr<Expression> clone() const override {
|
||||
return std::unique_ptr<Expression>(new BoolLiteral(fOffset, fValue, &fType));
|
||||
}
|
||||
|
@ -20,6 +20,10 @@ struct BreakStatement : public Statement {
|
||||
BreakStatement(int offset)
|
||||
: INHERITED(offset, kBreak_Kind) {}
|
||||
|
||||
int nodeCount() const override {
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::unique_ptr<Statement> clone() const override {
|
||||
return std::unique_ptr<Statement>(new BreakStatement(fOffset));
|
||||
}
|
||||
|
@ -59,6 +59,14 @@ struct Constructor : public Expression {
|
||||
return false;
|
||||
}
|
||||
|
||||
int nodeCount() const override {
|
||||
int result = 1;
|
||||
for (const auto& a : fArguments) {
|
||||
result += a->nodeCount();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::unique_ptr<Expression> clone() const override {
|
||||
std::vector<std::unique_ptr<Expression>> cloned;
|
||||
for (const auto& arg : fArguments) {
|
||||
|
@ -20,6 +20,10 @@ struct ContinueStatement : public Statement {
|
||||
ContinueStatement(int offset)
|
||||
: INHERITED(offset, kContinue_Kind) {}
|
||||
|
||||
int nodeCount() const override {
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::unique_ptr<Statement> clone() const override {
|
||||
return std::unique_ptr<Statement>(new ContinueStatement(fOffset));
|
||||
}
|
||||
|
@ -20,6 +20,10 @@ struct DiscardStatement : public Statement {
|
||||
DiscardStatement(int offset)
|
||||
: INHERITED(offset, kDiscard_Kind) {}
|
||||
|
||||
int nodeCount() const override {
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::unique_ptr<Statement> clone() const override {
|
||||
return std::unique_ptr<Statement>(new DiscardStatement(fOffset));
|
||||
}
|
||||
|
@ -23,6 +23,10 @@ struct DoStatement : public Statement {
|
||||
, fStatement(std::move(statement))
|
||||
, fTest(std::move(test)) {}
|
||||
|
||||
int nodeCount() const override {
|
||||
return 1 + fStatement->nodeCount() + fTest->nodeCount();
|
||||
}
|
||||
|
||||
std::unique_ptr<Statement> clone() const override {
|
||||
return std::unique_ptr<Statement>(new DoStatement(fOffset, fStatement->clone(),
|
||||
fTest->clone()));
|
||||
|
@ -21,6 +21,10 @@ struct ExpressionStatement : public Statement {
|
||||
: INHERITED(expression->fOffset, kExpression_Kind)
|
||||
, fExpression(std::move(expression)) {}
|
||||
|
||||
int nodeCount() const override {
|
||||
return 1 + fExpression->nodeCount();
|
||||
}
|
||||
|
||||
std::unique_ptr<Statement> clone() const override {
|
||||
return std::unique_ptr<Statement>(new ExpressionStatement(fExpression->clone()));
|
||||
}
|
||||
|
@ -36,6 +36,14 @@ struct ExternalFunctionCall : public Expression {
|
||||
return false;
|
||||
}
|
||||
|
||||
int nodeCount() const override {
|
||||
int result = 1;
|
||||
for (const auto& a : fArguments) {
|
||||
result += a->nodeCount();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::unique_ptr<Expression> clone() const override {
|
||||
std::vector<std::unique_ptr<Expression>> cloned;
|
||||
for (const auto& arg : fArguments) {
|
||||
|
@ -25,6 +25,10 @@ struct ExternalValueReference : public Expression {
|
||||
return property == Property::kSideEffects;
|
||||
}
|
||||
|
||||
int nodeCount() const override {
|
||||
return 1;
|
||||
}
|
||||
|
||||
String description() const override {
|
||||
return String(fValue->fName);
|
||||
}
|
||||
|
@ -35,6 +35,10 @@ struct FieldAccess : public Expression {
|
||||
return fBase->hasProperty(property);
|
||||
}
|
||||
|
||||
int nodeCount() const override {
|
||||
return 1 + fBase->nodeCount();
|
||||
}
|
||||
|
||||
std::unique_ptr<Expression> clone() const override {
|
||||
return std::unique_ptr<Expression>(new FieldAccess(fBase->clone(), fFieldIndex,
|
||||
fOwnerKind));
|
||||
|
@ -53,6 +53,10 @@ struct FloatLiteral : public Expression {
|
||||
return fValue;
|
||||
}
|
||||
|
||||
int nodeCount() const override {
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::unique_ptr<Expression> clone() const override {
|
||||
return std::unique_ptr<Expression>(new FloatLiteral(fOffset, fValue, &fType));
|
||||
}
|
||||
|
@ -28,16 +28,36 @@ struct ForStatement : public Statement {
|
||||
, fNext(std::move(next))
|
||||
, fStatement(std::move(statement)) {}
|
||||
|
||||
int nodeCount() const override {
|
||||
int result = 1;
|
||||
if (fInitializer) {
|
||||
result += fInitializer->nodeCount();
|
||||
}
|
||||
if (fTest) {
|
||||
result += fTest->nodeCount();
|
||||
}
|
||||
if (fNext) {
|
||||
result += fNext->nodeCount();
|
||||
}
|
||||
result += fStatement->nodeCount();
|
||||
return result;
|
||||
}
|
||||
|
||||
std::unique_ptr<Statement> clone() const override {
|
||||
return std::unique_ptr<Statement>(new ForStatement(fOffset, fInitializer->clone(),
|
||||
fTest->clone(), fNext->clone(),
|
||||
fStatement->clone(), fSymbols));
|
||||
return std::unique_ptr<Statement>(new ForStatement(fOffset,
|
||||
fInitializer ? fInitializer->clone() : nullptr,
|
||||
fTest ? fTest->clone() : nullptr,
|
||||
fNext ? fNext->clone() : nullptr,
|
||||
fStatement->clone(),
|
||||
fSymbols));
|
||||
}
|
||||
|
||||
String description() const override {
|
||||
String result("for (");
|
||||
if (fInitializer) {
|
||||
result += fInitializer->description();
|
||||
} else {
|
||||
result += ";";
|
||||
}
|
||||
result += " ";
|
||||
if (fTest) {
|
||||
|
@ -36,6 +36,14 @@ struct FunctionCall : public Expression {
|
||||
return false;
|
||||
}
|
||||
|
||||
int nodeCount() const override {
|
||||
int result = 1;
|
||||
for (const auto& a : fArguments) {
|
||||
result += a->nodeCount();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::unique_ptr<Expression> clone() const override {
|
||||
std::vector<std::unique_ptr<Expression>> cloned;
|
||||
for (const auto& arg : fArguments) {
|
||||
|
@ -17,6 +17,8 @@
|
||||
|
||||
namespace SkSL {
|
||||
|
||||
struct FunctionDefinition;
|
||||
|
||||
/**
|
||||
* A function declaration (not a definition -- does not contain a body).
|
||||
*/
|
||||
@ -24,7 +26,7 @@ struct FunctionDeclaration : public Symbol {
|
||||
FunctionDeclaration(int offset, Modifiers modifiers, StringFragment name,
|
||||
std::vector<const Variable*> parameters, const Type& returnType)
|
||||
: INHERITED(offset, kFunctionDeclaration_Kind, std::move(name))
|
||||
, fDefined(false)
|
||||
, fDefinition(nullptr)
|
||||
, fBuiltin(false)
|
||||
, fModifiers(modifiers)
|
||||
, fParameters(std::move(parameters))
|
||||
@ -107,7 +109,7 @@ struct FunctionDeclaration : public Symbol {
|
||||
return true;
|
||||
}
|
||||
|
||||
mutable bool fDefined;
|
||||
mutable FunctionDefinition* fDefinition;
|
||||
bool fBuiltin;
|
||||
Modifiers fModifiers;
|
||||
const std::vector<const Variable*> fParameters;
|
||||
|
@ -26,6 +26,11 @@ struct FunctionDefinition : public ProgramElement {
|
||||
, fDeclaration(declaration)
|
||||
, fBody(std::move(body)) {}
|
||||
|
||||
bool canBeInlined() const {
|
||||
static const int INLINE_THRESHOLD = 50; // chosen arbitrarily, feel free to adjust
|
||||
return fBody->nodeCount() < INLINE_THRESHOLD;
|
||||
}
|
||||
|
||||
std::unique_ptr<ProgramElement> clone() const override {
|
||||
return std::unique_ptr<ProgramElement>(new FunctionDefinition(fOffset, fDeclaration,
|
||||
fBody->clone()));
|
||||
|
@ -23,6 +23,12 @@ struct IRNode {
|
||||
|
||||
virtual ~IRNode() {}
|
||||
|
||||
virtual int nodeCount() const {
|
||||
SkASSERT(false);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
virtual String description() const = 0;
|
||||
|
||||
// character offset of this element within the program being compiled, for error reporting
|
||||
|
@ -25,6 +25,11 @@ struct IfStatement : public Statement {
|
||||
, fIfTrue(std::move(ifTrue))
|
||||
, fIfFalse(std::move(ifFalse)) {}
|
||||
|
||||
int nodeCount() const override {
|
||||
return 1 + fTest->nodeCount() + fIfTrue->nodeCount() +
|
||||
(fIfFalse ? fIfFalse->nodeCount() : 0);
|
||||
}
|
||||
|
||||
std::unique_ptr<Statement> clone() const override {
|
||||
return std::unique_ptr<Statement>(new IfStatement(fOffset, fIsStatic, fTest->clone(),
|
||||
fIfTrue->clone(), fIfFalse ? fIfFalse->clone() : nullptr));
|
||||
|
@ -62,6 +62,10 @@ struct IndexExpression : public Expression {
|
||||
return fBase->hasProperty(property) || fIndex->hasProperty(property);
|
||||
}
|
||||
|
||||
int nodeCount() const override {
|
||||
return 1 + fBase->nodeCount() + fIndex->nodeCount();
|
||||
}
|
||||
|
||||
std::unique_ptr<Expression> clone() const override {
|
||||
return std::unique_ptr<Expression>(new IndexExpression(fBase->clone(), fIndex->clone(),
|
||||
&fType));
|
||||
|
@ -56,6 +56,10 @@ struct IntLiteral : public Expression {
|
||||
return fValue;
|
||||
}
|
||||
|
||||
int nodeCount() const override {
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::unique_ptr<Expression> clone() const override {
|
||||
return std::unique_ptr<Expression>(new IntLiteral(fOffset, fValue, &fType));
|
||||
}
|
||||
|
@ -28,6 +28,10 @@ struct Nop : public Statement {
|
||||
return String(";");
|
||||
}
|
||||
|
||||
int nodeCount() const override {
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::unique_ptr<Statement> clone() const override {
|
||||
return std::unique_ptr<Statement>(new Nop());
|
||||
}
|
||||
|
@ -39,6 +39,10 @@ struct NullLiteral : public Expression {
|
||||
return true;
|
||||
}
|
||||
|
||||
int nodeCount() const override {
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::unique_ptr<Expression> clone() const override {
|
||||
return std::unique_ptr<Expression>(new NullLiteral(fOffset, fType));
|
||||
}
|
||||
|
@ -30,6 +30,10 @@ struct PostfixExpression : public Expression {
|
||||
return fOperand->hasProperty(property);
|
||||
}
|
||||
|
||||
int nodeCount() const override {
|
||||
return 1 + fOperand->nodeCount();
|
||||
}
|
||||
|
||||
std::unique_ptr<Expression> clone() const override {
|
||||
return std::unique_ptr<Expression>(new PostfixExpression(fOperand->clone(), fOperator));
|
||||
}
|
||||
|
@ -64,6 +64,10 @@ struct PrefixExpression : public Expression {
|
||||
return -fOperand->getMatComponent(col, row);
|
||||
}
|
||||
|
||||
int nodeCount() const override {
|
||||
return 1 + fOperand->nodeCount();
|
||||
}
|
||||
|
||||
std::unique_ptr<Expression> clone() const override {
|
||||
return std::unique_ptr<Expression>(new PrefixExpression(fOperator, fOperand->clone()));
|
||||
}
|
||||
|
@ -24,6 +24,10 @@ struct ReturnStatement : public Statement {
|
||||
: INHERITED(expression->fOffset, kReturn_Kind)
|
||||
, fExpression(std::move(expression)) {}
|
||||
|
||||
int nodeCount() const override {
|
||||
return 1 + fExpression->nodeCount();
|
||||
}
|
||||
|
||||
std::unique_ptr<Statement> clone() const override {
|
||||
if (fExpression) {
|
||||
return std::unique_ptr<Statement>(new ReturnStatement(fExpression->clone()));
|
||||
|
@ -28,6 +28,10 @@ struct Setting : public Expression {
|
||||
std::unique_ptr<Expression> constantPropagate(const IRGenerator& irGenerator,
|
||||
const DefinitionMap& definitions) override;
|
||||
|
||||
int nodeCount() const override {
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::unique_ptr<Expression> clone() const override {
|
||||
return std::unique_ptr<Expression>(new Setting(fOffset, fName, fValue->clone()));
|
||||
}
|
||||
|
@ -25,7 +25,6 @@ struct Statement : public IRNode {
|
||||
kDo_Kind,
|
||||
kExpression_Kind,
|
||||
kFor_Kind,
|
||||
kGroup_Kind,
|
||||
kIf_Kind,
|
||||
kNop_Kind,
|
||||
kReturn_Kind,
|
||||
|
@ -23,6 +23,17 @@ struct SwitchCase : public Statement {
|
||||
, fValue(std::move(value))
|
||||
, fStatements(std::move(statements)) {}
|
||||
|
||||
int nodeCount() const override {
|
||||
int result = 1;
|
||||
if (fValue) {
|
||||
result += fValue->nodeCount();
|
||||
}
|
||||
for (const auto& s : fStatements) {
|
||||
result += s->nodeCount();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::unique_ptr<Statement> clone() const override {
|
||||
std::vector<std::unique_ptr<Statement>> cloned;
|
||||
for (const auto& s : fStatements) {
|
||||
|
@ -28,6 +28,14 @@ struct SwitchStatement : public Statement {
|
||||
, fSymbols(std::move(symbols))
|
||||
, fCases(std::move(cases)) {}
|
||||
|
||||
int nodeCount() const override {
|
||||
int result = 1 + fValue->nodeCount();
|
||||
for (const auto& c : fCases) {
|
||||
result += c->nodeCount();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::unique_ptr<Statement> clone() const override {
|
||||
std::vector<std::unique_ptr<SwitchCase>> cloned;
|
||||
for (const auto& s : fCases) {
|
||||
|
@ -136,6 +136,10 @@ struct Swizzle : public Expression {
|
||||
return fBase->hasProperty(property);
|
||||
}
|
||||
|
||||
int nodeCount() const override {
|
||||
return 1 + fBase->nodeCount();
|
||||
}
|
||||
|
||||
std::unique_ptr<Expression> clone() const override {
|
||||
return std::unique_ptr<Expression>(new Swizzle(fType, fBase->clone(), fComponents));
|
||||
}
|
||||
|
@ -30,7 +30,7 @@ struct Symbol : public IRNode {
|
||||
, fKind(kind)
|
||||
, fName(name) {}
|
||||
|
||||
virtual ~Symbol() {}
|
||||
virtual ~Symbol() override {}
|
||||
|
||||
Kind fKind;
|
||||
StringFragment fName;
|
||||
|
@ -72,6 +72,12 @@ IRNode* SymbolTable::takeOwnership(std::unique_ptr<IRNode> n) {
|
||||
return result;
|
||||
}
|
||||
|
||||
String* SymbolTable::takeOwnership(std::unique_ptr<String> n) {
|
||||
String* result = n.get();
|
||||
fOwnedStrings.push_back(std::move(n));
|
||||
return result;
|
||||
}
|
||||
|
||||
void SymbolTable::add(StringFragment name, std::unique_ptr<Symbol> symbol) {
|
||||
this->addWithoutOwnership(name, symbol.get());
|
||||
this->takeOwnership(std::move(symbol));
|
||||
|
@ -41,6 +41,8 @@ public:
|
||||
|
||||
IRNode* takeOwnership(std::unique_ptr<IRNode> n);
|
||||
|
||||
String* takeOwnership(std::unique_ptr<String> n);
|
||||
|
||||
void markAllFunctionsBuiltin();
|
||||
|
||||
std::unordered_map<StringFragment, const Symbol*>::iterator begin();
|
||||
@ -56,6 +58,8 @@ private:
|
||||
|
||||
std::vector<std::unique_ptr<IRNode>> fOwnedNodes;
|
||||
|
||||
std::vector<std::unique_ptr<String>> fOwnedStrings;
|
||||
|
||||
std::unordered_map<StringFragment, const Symbol*> fSymbols;
|
||||
|
||||
ErrorReporter& fErrorReporter;
|
||||
|
@ -36,6 +36,10 @@ struct TernaryExpression : public Expression {
|
||||
fIfFalse->isConstantOrUniform();
|
||||
}
|
||||
|
||||
int nodeCount() const override {
|
||||
return 1 + fTest->nodeCount() + fIfTrue->nodeCount() + fIfFalse->nodeCount();
|
||||
}
|
||||
|
||||
std::unique_ptr<Expression> clone() const override {
|
||||
return std::unique_ptr<Expression>(new TernaryExpression(fOffset, fTest->clone(),
|
||||
fIfTrue->clone(),
|
||||
|
@ -29,6 +29,19 @@ struct VarDeclaration : public Statement {
|
||||
, fSizes(std::move(sizes))
|
||||
, fValue(std::move(value)) {}
|
||||
|
||||
int nodeCount() const override {
|
||||
int result = 1;
|
||||
for (const auto& s : fSizes) {
|
||||
if (s) {
|
||||
result += s->nodeCount();
|
||||
}
|
||||
}
|
||||
if (fValue) {
|
||||
result += fValue->nodeCount();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::unique_ptr<Statement> clone() const override {
|
||||
std::vector<std::unique_ptr<Expression>> sizesClone;
|
||||
for (const auto& s : fSizes) {
|
||||
@ -77,6 +90,14 @@ struct VarDeclarations : public ProgramElement {
|
||||
}
|
||||
}
|
||||
|
||||
int nodeCount() const override {
|
||||
int result = 1;
|
||||
for (const auto& v : fVars) {
|
||||
result += v->nodeCount();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::unique_ptr<ProgramElement> clone() const override {
|
||||
std::vector<std::unique_ptr<VarDeclaration>> cloned;
|
||||
for (const auto& v : fVars) {
|
||||
@ -91,8 +112,15 @@ struct VarDeclarations : public ProgramElement {
|
||||
if (!fVars.size()) {
|
||||
return String();
|
||||
}
|
||||
String result = ((VarDeclaration&) *fVars[0]).fVar->fModifiers.description() +
|
||||
fBaseType.description() + " ";
|
||||
String result;
|
||||
for (const auto& var : fVars) {
|
||||
if (var->fKind != Statement::kNop_Kind) {
|
||||
SkASSERT(var->fKind == Statement::kVarDeclaration_Kind);
|
||||
result = ((const VarDeclaration&) *var).fVar->fModifiers.description();
|
||||
break;
|
||||
}
|
||||
}
|
||||
result += fBaseType.description() + " ";
|
||||
String separator;
|
||||
for (const auto& var : fVars) {
|
||||
result += separator;
|
||||
|
@ -30,6 +30,10 @@ struct VarDeclarationsStatement : public Statement {
|
||||
return true;
|
||||
}
|
||||
|
||||
int nodeCount() const override {
|
||||
return 1 + fDeclaration->nodeCount();
|
||||
}
|
||||
|
||||
std::unique_ptr<Statement> clone() const override {
|
||||
std::unique_ptr<VarDeclarations> cloned((VarDeclarations*) fDeclaration->clone().release());
|
||||
return std::unique_ptr<Statement>(new VarDeclarationsStatement(std::move(cloned)));
|
||||
|
@ -62,6 +62,10 @@ struct VariableReference : public Expression {
|
||||
return (fVariable.fModifiers.fFlags & Modifiers::kUniform_Flag) != 0;
|
||||
}
|
||||
|
||||
int nodeCount() const override {
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::unique_ptr<Expression> clone() const override {
|
||||
return std::unique_ptr<Expression>(new VariableReference(fOffset, fVariable, fRefKind));
|
||||
}
|
||||
|
@ -23,6 +23,10 @@ struct WhileStatement : public Statement {
|
||||
, fTest(std::move(test))
|
||||
, fStatement(std::move(statement)) {}
|
||||
|
||||
int nodeCount() const override {
|
||||
return 1 + fTest->nodeCount() + fStatement->nodeCount();
|
||||
}
|
||||
|
||||
std::unique_ptr<Statement> clone() const override {
|
||||
return std::unique_ptr<Statement>(new WhileStatement(fOffset, fTest->clone(),
|
||||
fStatement->clone()));
|
||||
|
@ -371,7 +371,7 @@ DEF_TEST(SkSLUnreachable, r) {
|
||||
"void main() { if (true) return; else discard; return; }",
|
||||
"error: 1: unreachable\n1 error\n");
|
||||
test_failure(r,
|
||||
"void main() { return; while (true); }",
|
||||
"void main() { return; main(); }",
|
||||
"error: 1: unreachable\n1 error\n");
|
||||
}
|
||||
|
||||
|
@ -784,8 +784,11 @@ DEF_TEST(SkSLFPFunction, r) {
|
||||
"const GrShaderVar flip_args[] = { GrShaderVar(\"c\", kHalf4_GrSLType)};",
|
||||
"fragBuilder->emitFunction(kHalf4_GrSLType, \"flip\", 1, flip_args, "
|
||||
"\"return c.wzyx;\\n\", &flip_name);",
|
||||
"fragBuilder->codeAppendf(\"%s = %s(%s);\\n\", args.fOutputColor, flip_name.c_str(), "
|
||||
"args.fInputColor);"
|
||||
"fragBuilder->codeAppendf(\"half4 inlineResult101;\\nhalf4 inlineArg101_0 = %s;\\ndo {"
|
||||
"\\n {\\n inlineResult101 = inlineArg101_0.wzyx;\\n"
|
||||
" break;\\n }\\n} while (false);\\n%s = "
|
||||
"inlineResult101;\\n\\n\", args.fInputColor, "
|
||||
"args.fOutputColor);"
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -111,7 +111,16 @@ DEF_TEST(SkSLFunctions, r) {
|
||||
" float y[2], z;\n"
|
||||
" y[0] = x;\n"
|
||||
" y[1] = x * 2.0;\n"
|
||||
" z = foo(y);\n"
|
||||
" float inlineResult117;\n"
|
||||
" float[2] inlineArg117_0 = y;\n"
|
||||
" do {\n"
|
||||
" {\n"
|
||||
" inlineResult117 = inlineArg117_0[0] * inlineArg117_0[1];\n"
|
||||
" break;\n"
|
||||
" }\n"
|
||||
" } while (false);\n"
|
||||
" z = inlineResult117;\n"
|
||||
"\n"
|
||||
" x = z;\n"
|
||||
"}\n"
|
||||
"void main() {\n"
|
||||
|
Loading…
Reference in New Issue
Block a user