diff --git a/src/gpu/effects/generated/GrColorMatrixFragmentProcessor.cpp b/src/gpu/effects/generated/GrColorMatrixFragmentProcessor.cpp index 94d81a0236..ceb17fd9ea 100644 --- a/src/gpu/effects/generated/GrColorMatrixFragmentProcessor.cpp +++ b/src/gpu/effects/generated/GrColorMatrixFragmentProcessor.cpp @@ -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), diff --git a/src/sksl/SkSLASTNode.cpp b/src/sksl/SkSLASTNode.cpp index 7c5a2033a0..a74d5ab338 100644 --- a/src/sksl/SkSLASTNode.cpp +++ b/src/sksl/SkSLASTNode.cpp @@ -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 ""; diff --git a/src/sksl/SkSLCompiler.cpp b/src/sksl/SkSLCompiler.cpp index fe75fe784b..85f4bb6d7f 100644 --- a/src/sksl/SkSLCompiler.cpp +++ b/src/sksl/SkSLCompiler.cpp @@ -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")); diff --git a/src/sksl/SkSLContext.h b/src/sksl/SkSLContext.h index eb7659a072..39968d42bf 100644 --- a/src/sksl/SkSLContext.h +++ b/src/sksl/SkSLContext.h @@ -400,6 +400,11 @@ private: return ""; } + int nodeCount() const override { + SkASSERT(false); + return 1; + } + std::unique_ptr clone() const override { return std::unique_ptr(new Defined(fType)); } diff --git a/src/sksl/SkSLGLSLCodeGenerator.cpp b/src/sksl/SkSLGLSLCodeGenerator.cpp index e21c32c2c2..0aa7bbc667 100644 --- a/src/sksl/SkSLGLSLCodeGenerator.cpp +++ b/src/sksl/SkSLGLSLCodeGenerator.cpp @@ -1521,11 +1521,15 @@ void GLSLCodeGenerator::writeStatements(const std::vectorwriteLine("{"); - 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) { diff --git a/src/sksl/SkSLIRGenerator.cpp b/src/sksl/SkSLIRGenerator.cpp index 8f2b1c5089..bdecf7e0dc 100644 --- a/src/sksl/SkSLIRGenerator.cpp +++ b/src/sksl/SkSLIRGenerator.cpp @@ -182,7 +182,7 @@ void IRGenerator::finish() { fSettings = nullptr; } -std::unique_ptr IRGenerator::convertStatement(const ASTNode& statement) { +std::unique_ptr IRGenerator::convertSingleStatement(const ASTNode& statement) { switch (statement.fKind) { case ASTNode::Kind::kBlock: return this->convertBlock(statement); @@ -228,6 +228,24 @@ std::unique_ptr IRGenerator::convertStatement(const ASTNode& statemen } } +std::unique_ptr IRGenerator::convertStatement(const ASTNode& statement) { + std::vector> oldExtraStatements = std::move(fExtraStatements); + std::unique_ptr result = this->convertSingleStatement(statement); + if (!result) { + fExtraStatements = std::move(oldExtraStatements); + return nullptr; + } + if (fExtraStatements.size()) { + fExtraStatements.push_back(std::move(result)); + std::unique_ptr block(new Block(-1, std::move(fExtraStatements), nullptr, + false)); + fExtraStatements = std::move(oldExtraStatements); + return block; + } + fExtraStatements = std::move(oldExtraStatements); + return result; +} + std::unique_ptr IRGenerator::convertBlock(const ASTNode& block) { SkASSERT(block.fKind == ASTNode::Kind::kBlock); AutoSymbolTable table(this); @@ -496,15 +514,22 @@ std::unique_ptr IRGenerator::convertFor(const ASTNode& f) { ++iter; std::unique_ptr 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 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 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 test = this->coerce(this->convertExpression(*(iter++)), *fContext.fBool_Type); + fCanInline = oldCanInline; if (!test) { return nullptr; } @@ -545,8 +573,11 @@ std::unique_ptr IRGenerator::convertDo(const ASTNode& d) { if (!statement) { return nullptr; } + bool oldCanInline = fCanInline; + fCanInline = false; std::unique_ptr 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 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 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 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 right = this->convertExpression(*(iter++)); + fCanInline = oldCanInline; if (!right) { return nullptr; } @@ -1734,7 +1773,6 @@ std::unique_ptr 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 IRGenerator::convertTernaryExpression(const ASTNode& std::move(ifFalse))); } +std::unique_ptr IRGenerator::inlineExpression(int offset, + std::map* varMap, + const Expression& expression) { + auto expr = [&](const std::unique_ptr& e) { + if (e) { + return this->inlineExpression(offset, varMap, *e); + } + return std::unique_ptr(nullptr); + }; + switch (expression.fKind) { + case Expression::kBinary_Kind: { + const BinaryExpression& b = (const BinaryExpression&) expression; + return std::unique_ptr(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> args; + for (const auto& arg : c.fArguments) { + args.push_back(expr(arg)); + } + return std::unique_ptr(new Constructor(offset, c.fType, std::move(args))); + } + case Expression::kExternalFunctionCall_Kind: { + const ExternalFunctionCall& e = (const ExternalFunctionCall&) expression; + std::vector> args; + for (const auto& arg : e.fArguments) { + args.push_back(expr(arg)); + } + return std::unique_ptr(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(new FieldAccess(expr(f.fBase), f.fFieldIndex, + f.fOwnerKind)); + } + case Expression::kFunctionCall_Kind: { + const FunctionCall& c = (const FunctionCall&) expression; + std::vector> args; + for (const auto& arg : c.fArguments) { + args.push_back(expr(arg)); + } + return std::unique_ptr(new FunctionCall(offset, c.fType, c.fFunction, + std::move(args))); + } + case Expression::kIndex_Kind: { + const IndexExpression& idx = (const IndexExpression&) expression; + return std::unique_ptr(new IndexExpression(fContext, expr(idx.fBase), + expr(idx.fIndex))); + } + case Expression::kPrefix_Kind: { + const PrefixExpression& p = (const PrefixExpression&) expression; + return std::unique_ptr(new PrefixExpression(p.fOperator, expr(p.fOperand))); + } + case Expression::kPostfix_Kind: { + const PostfixExpression& p = (const PostfixExpression&) expression; + return std::unique_ptr(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(new Swizzle(fContext, expr(s.fBase), s.fComponents)); + } + case Expression::kTernary_Kind: { + const TernaryExpression& t = (const TernaryExpression&) expression; + return std::unique_ptr(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(new VariableReference(offset, + *found->second, + v.fRefKind)); + } + return v.clone(); + } + default: + SkASSERT(false); + return nullptr; + } +} + +std::unique_ptr IRGenerator::inlineStatement(int offset, + std::map* varMap, + const Variable* returnVar, + const Statement& statement) { + auto stmt = [&](const std::unique_ptr& s) { + if (s) { + return this->inlineStatement(offset, varMap, returnVar, *s); + } + return std::unique_ptr(nullptr); + }; + auto stmts = [&](const std::vector>& ss) { + std::vector> result; + for (const auto& s : ss) { + result.push_back(stmt(s)); + } + return result; + }; + auto expr = [&](const std::unique_ptr& e) { + if (e) { + return this->inlineExpression(offset, varMap, *e); + } + return std::unique_ptr(nullptr); + }; + switch (statement.fKind) { + case Statement::kBlock_Kind: { + const Block& b = (const Block&) statement; + return std::unique_ptr(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(new DoStatement(offset, + stmt(d.fStatement), + expr(d.fTest))); + } + case Statement::kExpression_Kind: { + const ExpressionStatement& e = (const ExpressionStatement&) statement; + return std::unique_ptr(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 initializer = stmt(f.fInitializer); + return std::unique_ptr(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(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> block; + block.emplace_back(new ExpressionStatement( + std::unique_ptr(new BinaryExpression(offset, + std::unique_ptr(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(new Block(offset, std::move(block))); + } else { + return std::unique_ptr(new BreakStatement(offset)); + } + } + case Statement::kSwitch_Kind: { + const SwitchStatement& ss = (const SwitchStatement&) statement; + std::vector> cases; + for (const auto& sc : ss.fCases) { + cases.emplace_back(new SwitchCase(offset, expr(sc->fValue), + stmts(sc->fStatements))); + } + return std::unique_ptr(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> sizes; + for (const auto& size : decl.fSizes) { + sizes.push_back(expr(size)); + } + std::unique_ptr initialValue = expr(decl.fValue); + const Variable* old = decl.fVar; + Variable* clone = (Variable*) fSymbolTable->takeOwnership(std::unique_ptr( + new Variable(offset, old->fModifiers, old->fName, + old->fType, old->fStorage, + initialValue.get()))); + (*varMap)[old] = clone; + return std::unique_ptr(new VarDeclaration(clone, std::move(sizes), + std::move(initialValue))); + } + case Statement::kVarDeclarations_Kind: { + const VarDeclarations& decls = *((VarDeclarationsStatement&) statement).fDeclaration; + std::vector> vars; + for (const auto& var : decls.fVars) { + vars.emplace_back((VarDeclaration*) stmt(var).release()); + } + return std::unique_ptr(new VarDeclarationsStatement( + std::unique_ptr(new VarDeclarations(offset, &decls.fBaseType, + std::move(vars))))); + } + case Statement::kWhile_Kind: { + const WhileStatement& w = (const WhileStatement&) statement; + return std::unique_ptr(new WhileStatement(offset, + expr(w.fTest), + stmt(w.fStatement))); + } + default: + SkASSERT(false); + return nullptr; + } +} + +std::unique_ptr IRGenerator::inlineCall( + int offset, + const FunctionDefinition& function, + std::vector> 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> body; + Variable* resultVar; + if (function.fDeclaration.fReturnType != *fContext.fVoid_Type) { + std::unique_ptr name(new String()); + name->appendf("inlineResult%d", offset); + String* namePtr = (String*) fSymbolTable->takeOwnership(std::move(name)); + resultVar = (Variable*) fSymbolTable->takeOwnership(std::unique_ptr( + new Variable(-1, Modifiers(), namePtr->c_str(), + function.fDeclaration.fReturnType, + Variable::kLocal_Storage, + nullptr))); + std::vector> variables; + variables.emplace_back(new VarDeclaration(resultVar, {}, nullptr)); + fExtraStatements.emplace_back(new VarDeclarationsStatement( + std::unique_ptr(new VarDeclarations(offset, + &resultVar->fType, + std::move(variables))))); + + } else { + resultVar = nullptr; + } + std::map 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 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( + new Variable(-1, Modifiers(), + argNamePtr->c_str(), + arguments[i]->fType, + Variable::kLocal_Storage, + arguments[i].get()))); + varMap[function.fDeclaration.fParameters[i]] = argVar; + std::vector> 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(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(new Block(-1, std::move(body))), + std::unique_ptr(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 varRef(new VariableReference(offset, *varMap[p])); + fExtraStatements.emplace_back(new ExpressionStatement( + std::unique_ptr(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(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(new BoolLiteral(fContext, -1, false)); + } +} + + std::unique_ptr IRGenerator::call(int offset, const FunctionDeclaration& function, std::vector> arguments) { @@ -1835,7 +2191,7 @@ std::unique_ptr 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 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(new FunctionCall(offset, *returnType, function, std::move(arguments))); } diff --git a/src/sksl/SkSLIRGenerator.h b/src/sksl/SkSLIRGenerator.h index 2895a34dc4..4861fcf068 100644 --- a/src/sksl/SkSLIRGenerator.h +++ b/src/sksl/SkSLIRGenerator.h @@ -83,11 +83,21 @@ private: std::unique_ptr convertVarDeclarations(const ASTNode& decl, Variable::Storage storage); void convertFunction(const ASTNode& f); + std::unique_ptr convertSingleStatement(const ASTNode& statement); std::unique_ptr convertStatement(const ASTNode& statement); std::unique_ptr convertExpression(const ASTNode& expression); std::unique_ptr convertModifiersDeclaration(const ASTNode& m); const Type* convertType(const ASTNode& type); + std::unique_ptr inlineExpression(int offset, + std::map* varMap, + const Expression& expression); + std::unique_ptr inlineStatement(int offset, + std::map* varMap, + const Variable* returnVar, + const Statement& statement); + std::unique_ptr inlineCall(int offset, const FunctionDefinition& function, + std::vector> arguments); std::unique_ptr call(int offset, const FunctionDeclaration& function, std::vector> arguments); @@ -156,6 +166,9 @@ private: std::unordered_map fCapsMap; std::shared_ptr fRootSymbolTable; std::shared_ptr fSymbolTable; + // additional statements that need to be inserted before the one that convertStatement is + // currently working on + std::vector> fExtraStatements; // Symbols which have definitions in the include files. The bool tells us whether this // intrinsic has been included already. std::map, bool>>* fIntrinsics = nullptr; @@ -168,6 +181,7 @@ private: Variable* fRTAdjust; Variable* fRTAdjustInterfaceBlock; int fRTAdjustFieldIndex; + bool fCanInline = true; friend class AutoSymbolTable; friend class AutoLoopLevel; diff --git a/src/sksl/SkSLMetalCodeGenerator.cpp b/src/sksl/SkSLMetalCodeGenerator.cpp index 099ab4cb18..2b222d8ba1 100644 --- a/src/sksl/SkSLMetalCodeGenerator.cpp +++ b/src/sksl/SkSLMetalCodeGenerator.cpp @@ -1164,11 +1164,15 @@ void MetalCodeGenerator::writeStatements(const std::vectorwriteLine("{"); - 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) { diff --git a/src/sksl/SkSLSPIRVCodeGenerator.cpp b/src/sksl/SkSLSPIRVCodeGenerator.cpp index b01bd95c38..6726a8f3a1 100644 --- a/src/sksl/SkSLSPIRVCodeGenerator.cpp +++ b/src/sksl/SkSLSPIRVCodeGenerator.cpp @@ -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(); diff --git a/src/sksl/SkSLSectionAndParameterHelper.cpp b/src/sksl/SkSLSectionAndParameterHelper.cpp index a897386811..6d99548c7b 100644 --- a/src/sksl/SkSLSectionAndParameterHelper.cpp +++ b/src/sksl/SkSLSectionAndParameterHelper.cpp @@ -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(); +} + + } diff --git a/src/sksl/SkSLSectionAndParameterHelper.h b/src/sksl/SkSLSectionAndParameterHelper.h index d52302aabd..4bc7a47193 100644 --- a/src/sksl/SkSLSectionAndParameterHelper.h +++ b/src/sksl/SkSLSectionAndParameterHelper.h @@ -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; diff --git a/src/sksl/ir/SkSLBinaryExpression.h b/src/sksl/ir/SkSLBinaryExpression.h index 9fc8683e95..f4a48e94df 100644 --- a/src/sksl/ir/SkSLBinaryExpression.h +++ b/src/sksl/ir/SkSLBinaryExpression.h @@ -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 clone() const override { return std::unique_ptr(new BinaryExpression(fOffset, fLeft->clone(), fOperator, fRight->clone(), fType)); diff --git a/src/sksl/ir/SkSLBlock.h b/src/sksl/ir/SkSLBlock.h index 8a4449a01c..b9fdf29072 100644 --- a/src/sksl/ir/SkSLBlock.h +++ b/src/sksl/ir/SkSLBlock.h @@ -18,10 +18,11 @@ namespace SkSL { */ struct Block : public Statement { Block(int offset, std::vector> statements, - const std::shared_ptr symbols = nullptr) + const std::shared_ptr 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 clone() const override { std::vector> cloned; for (const auto& s : fStatements) { cloned.push_back(s->clone()); } - return std::unique_ptr(new Block(fOffset, std::move(cloned), fSymbols)); + return std::unique_ptr(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 fSymbols; std::vector> 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; }; diff --git a/src/sksl/ir/SkSLBoolLiteral.h b/src/sksl/ir/SkSLBoolLiteral.h index 74f48ad9b3..85dd8c5d0b 100644 --- a/src/sksl/ir/SkSLBoolLiteral.h +++ b/src/sksl/ir/SkSLBoolLiteral.h @@ -38,6 +38,10 @@ struct BoolLiteral : public Expression { return fValue == b.fValue; } + int nodeCount() const override { + return 1; + } + std::unique_ptr clone() const override { return std::unique_ptr(new BoolLiteral(fOffset, fValue, &fType)); } diff --git a/src/sksl/ir/SkSLBreakStatement.h b/src/sksl/ir/SkSLBreakStatement.h index ae0c1987e9..daedece915 100644 --- a/src/sksl/ir/SkSLBreakStatement.h +++ b/src/sksl/ir/SkSLBreakStatement.h @@ -20,6 +20,10 @@ struct BreakStatement : public Statement { BreakStatement(int offset) : INHERITED(offset, kBreak_Kind) {} + int nodeCount() const override { + return 1; + } + std::unique_ptr clone() const override { return std::unique_ptr(new BreakStatement(fOffset)); } diff --git a/src/sksl/ir/SkSLConstructor.h b/src/sksl/ir/SkSLConstructor.h index 524a6ad643..cdd6f84a94 100644 --- a/src/sksl/ir/SkSLConstructor.h +++ b/src/sksl/ir/SkSLConstructor.h @@ -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 clone() const override { std::vector> cloned; for (const auto& arg : fArguments) { diff --git a/src/sksl/ir/SkSLContinueStatement.h b/src/sksl/ir/SkSLContinueStatement.h index ecd9c3f497..1e01ac8e0e 100644 --- a/src/sksl/ir/SkSLContinueStatement.h +++ b/src/sksl/ir/SkSLContinueStatement.h @@ -20,6 +20,10 @@ struct ContinueStatement : public Statement { ContinueStatement(int offset) : INHERITED(offset, kContinue_Kind) {} + int nodeCount() const override { + return 1; + } + std::unique_ptr clone() const override { return std::unique_ptr(new ContinueStatement(fOffset)); } diff --git a/src/sksl/ir/SkSLDiscardStatement.h b/src/sksl/ir/SkSLDiscardStatement.h index 40f625c178..8cc7e3feec 100644 --- a/src/sksl/ir/SkSLDiscardStatement.h +++ b/src/sksl/ir/SkSLDiscardStatement.h @@ -20,6 +20,10 @@ struct DiscardStatement : public Statement { DiscardStatement(int offset) : INHERITED(offset, kDiscard_Kind) {} + int nodeCount() const override { + return 1; + } + std::unique_ptr clone() const override { return std::unique_ptr(new DiscardStatement(fOffset)); } diff --git a/src/sksl/ir/SkSLDoStatement.h b/src/sksl/ir/SkSLDoStatement.h index 5cab5c8bcd..474aac7839 100644 --- a/src/sksl/ir/SkSLDoStatement.h +++ b/src/sksl/ir/SkSLDoStatement.h @@ -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 clone() const override { return std::unique_ptr(new DoStatement(fOffset, fStatement->clone(), fTest->clone())); diff --git a/src/sksl/ir/SkSLExpressionStatement.h b/src/sksl/ir/SkSLExpressionStatement.h index 80a8d316c7..1732bbbcdb 100644 --- a/src/sksl/ir/SkSLExpressionStatement.h +++ b/src/sksl/ir/SkSLExpressionStatement.h @@ -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 clone() const override { return std::unique_ptr(new ExpressionStatement(fExpression->clone())); } diff --git a/src/sksl/ir/SkSLExternalFunctionCall.h b/src/sksl/ir/SkSLExternalFunctionCall.h index deb1f4d5cd..bf70561a5d 100644 --- a/src/sksl/ir/SkSLExternalFunctionCall.h +++ b/src/sksl/ir/SkSLExternalFunctionCall.h @@ -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 clone() const override { std::vector> cloned; for (const auto& arg : fArguments) { diff --git a/src/sksl/ir/SkSLExternalValueReference.h b/src/sksl/ir/SkSLExternalValueReference.h index aa0ec181ed..868c6c9bae 100644 --- a/src/sksl/ir/SkSLExternalValueReference.h +++ b/src/sksl/ir/SkSLExternalValueReference.h @@ -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); } diff --git a/src/sksl/ir/SkSLFieldAccess.h b/src/sksl/ir/SkSLFieldAccess.h index 59f4c166a1..6cba566340 100644 --- a/src/sksl/ir/SkSLFieldAccess.h +++ b/src/sksl/ir/SkSLFieldAccess.h @@ -35,6 +35,10 @@ struct FieldAccess : public Expression { return fBase->hasProperty(property); } + int nodeCount() const override { + return 1 + fBase->nodeCount(); + } + std::unique_ptr clone() const override { return std::unique_ptr(new FieldAccess(fBase->clone(), fFieldIndex, fOwnerKind)); diff --git a/src/sksl/ir/SkSLFloatLiteral.h b/src/sksl/ir/SkSLFloatLiteral.h index 79f5dcf701..9d81771994 100644 --- a/src/sksl/ir/SkSLFloatLiteral.h +++ b/src/sksl/ir/SkSLFloatLiteral.h @@ -53,6 +53,10 @@ struct FloatLiteral : public Expression { return fValue; } + int nodeCount() const override { + return 1; + } + std::unique_ptr clone() const override { return std::unique_ptr(new FloatLiteral(fOffset, fValue, &fType)); } diff --git a/src/sksl/ir/SkSLForStatement.h b/src/sksl/ir/SkSLForStatement.h index 4906e192a6..29c61bffa7 100644 --- a/src/sksl/ir/SkSLForStatement.h +++ b/src/sksl/ir/SkSLForStatement.h @@ -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 clone() const override { - return std::unique_ptr(new ForStatement(fOffset, fInitializer->clone(), - fTest->clone(), fNext->clone(), - fStatement->clone(), fSymbols)); + return std::unique_ptr(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) { diff --git a/src/sksl/ir/SkSLFunctionCall.h b/src/sksl/ir/SkSLFunctionCall.h index 296aa0b3ef..f575879de6 100644 --- a/src/sksl/ir/SkSLFunctionCall.h +++ b/src/sksl/ir/SkSLFunctionCall.h @@ -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 clone() const override { std::vector> cloned; for (const auto& arg : fArguments) { diff --git a/src/sksl/ir/SkSLFunctionDeclaration.h b/src/sksl/ir/SkSLFunctionDeclaration.h index f2a3e0fe66..0301ed7f0f 100644 --- a/src/sksl/ir/SkSLFunctionDeclaration.h +++ b/src/sksl/ir/SkSLFunctionDeclaration.h @@ -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 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 fParameters; diff --git a/src/sksl/ir/SkSLFunctionDefinition.h b/src/sksl/ir/SkSLFunctionDefinition.h index 511a0f8c20..4bcadcf57d 100644 --- a/src/sksl/ir/SkSLFunctionDefinition.h +++ b/src/sksl/ir/SkSLFunctionDefinition.h @@ -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 clone() const override { return std::unique_ptr(new FunctionDefinition(fOffset, fDeclaration, fBody->clone())); diff --git a/src/sksl/ir/SkSLIRNode.h b/src/sksl/ir/SkSLIRNode.h index ca9ea99998..cace825fe7 100644 --- a/src/sksl/ir/SkSLIRNode.h +++ b/src/sksl/ir/SkSLIRNode.h @@ -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 diff --git a/src/sksl/ir/SkSLIfStatement.h b/src/sksl/ir/SkSLIfStatement.h index 5d0a22b647..6af6740b0f 100644 --- a/src/sksl/ir/SkSLIfStatement.h +++ b/src/sksl/ir/SkSLIfStatement.h @@ -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 clone() const override { return std::unique_ptr(new IfStatement(fOffset, fIsStatic, fTest->clone(), fIfTrue->clone(), fIfFalse ? fIfFalse->clone() : nullptr)); diff --git a/src/sksl/ir/SkSLIndexExpression.h b/src/sksl/ir/SkSLIndexExpression.h index 2b3a3a93d5..2018881354 100644 --- a/src/sksl/ir/SkSLIndexExpression.h +++ b/src/sksl/ir/SkSLIndexExpression.h @@ -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 clone() const override { return std::unique_ptr(new IndexExpression(fBase->clone(), fIndex->clone(), &fType)); diff --git a/src/sksl/ir/SkSLIntLiteral.h b/src/sksl/ir/SkSLIntLiteral.h index 6c686e135b..4977fbf0b8 100644 --- a/src/sksl/ir/SkSLIntLiteral.h +++ b/src/sksl/ir/SkSLIntLiteral.h @@ -56,6 +56,10 @@ struct IntLiteral : public Expression { return fValue; } + int nodeCount() const override { + return 1; + } + std::unique_ptr clone() const override { return std::unique_ptr(new IntLiteral(fOffset, fValue, &fType)); } diff --git a/src/sksl/ir/SkSLNop.h b/src/sksl/ir/SkSLNop.h index 2ead371f87..787060d8b4 100644 --- a/src/sksl/ir/SkSLNop.h +++ b/src/sksl/ir/SkSLNop.h @@ -28,6 +28,10 @@ struct Nop : public Statement { return String(";"); } + int nodeCount() const override { + return 0; + } + std::unique_ptr clone() const override { return std::unique_ptr(new Nop()); } diff --git a/src/sksl/ir/SkSLNullLiteral.h b/src/sksl/ir/SkSLNullLiteral.h index d04fc5cb20..0d04b77e22 100644 --- a/src/sksl/ir/SkSLNullLiteral.h +++ b/src/sksl/ir/SkSLNullLiteral.h @@ -39,6 +39,10 @@ struct NullLiteral : public Expression { return true; } + int nodeCount() const override { + return 1; + } + std::unique_ptr clone() const override { return std::unique_ptr(new NullLiteral(fOffset, fType)); } diff --git a/src/sksl/ir/SkSLPostfixExpression.h b/src/sksl/ir/SkSLPostfixExpression.h index d95f687e37..c6f89eb2d6 100644 --- a/src/sksl/ir/SkSLPostfixExpression.h +++ b/src/sksl/ir/SkSLPostfixExpression.h @@ -30,6 +30,10 @@ struct PostfixExpression : public Expression { return fOperand->hasProperty(property); } + int nodeCount() const override { + return 1 + fOperand->nodeCount(); + } + std::unique_ptr clone() const override { return std::unique_ptr(new PostfixExpression(fOperand->clone(), fOperator)); } diff --git a/src/sksl/ir/SkSLPrefixExpression.h b/src/sksl/ir/SkSLPrefixExpression.h index 76f144b7fb..ab0363ec66 100644 --- a/src/sksl/ir/SkSLPrefixExpression.h +++ b/src/sksl/ir/SkSLPrefixExpression.h @@ -64,6 +64,10 @@ struct PrefixExpression : public Expression { return -fOperand->getMatComponent(col, row); } + int nodeCount() const override { + return 1 + fOperand->nodeCount(); + } + std::unique_ptr clone() const override { return std::unique_ptr(new PrefixExpression(fOperator, fOperand->clone())); } diff --git a/src/sksl/ir/SkSLReturnStatement.h b/src/sksl/ir/SkSLReturnStatement.h index e61fa36c74..82b4678106 100644 --- a/src/sksl/ir/SkSLReturnStatement.h +++ b/src/sksl/ir/SkSLReturnStatement.h @@ -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 clone() const override { if (fExpression) { return std::unique_ptr(new ReturnStatement(fExpression->clone())); diff --git a/src/sksl/ir/SkSLSetting.h b/src/sksl/ir/SkSLSetting.h index a47b42be91..9a69802b57 100644 --- a/src/sksl/ir/SkSLSetting.h +++ b/src/sksl/ir/SkSLSetting.h @@ -28,6 +28,10 @@ struct Setting : public Expression { std::unique_ptr constantPropagate(const IRGenerator& irGenerator, const DefinitionMap& definitions) override; + int nodeCount() const override { + return 1; + } + std::unique_ptr clone() const override { return std::unique_ptr(new Setting(fOffset, fName, fValue->clone())); } diff --git a/src/sksl/ir/SkSLStatement.h b/src/sksl/ir/SkSLStatement.h index ed8d33b142..2260cdd5a4 100644 --- a/src/sksl/ir/SkSLStatement.h +++ b/src/sksl/ir/SkSLStatement.h @@ -25,7 +25,6 @@ struct Statement : public IRNode { kDo_Kind, kExpression_Kind, kFor_Kind, - kGroup_Kind, kIf_Kind, kNop_Kind, kReturn_Kind, diff --git a/src/sksl/ir/SkSLSwitchCase.h b/src/sksl/ir/SkSLSwitchCase.h index b1ddb012ec..dcfe956426 100644 --- a/src/sksl/ir/SkSLSwitchCase.h +++ b/src/sksl/ir/SkSLSwitchCase.h @@ -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 clone() const override { std::vector> cloned; for (const auto& s : fStatements) { diff --git a/src/sksl/ir/SkSLSwitchStatement.h b/src/sksl/ir/SkSLSwitchStatement.h index 0777c5c5c6..a85420a695 100644 --- a/src/sksl/ir/SkSLSwitchStatement.h +++ b/src/sksl/ir/SkSLSwitchStatement.h @@ -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 clone() const override { std::vector> cloned; for (const auto& s : fCases) { diff --git a/src/sksl/ir/SkSLSwizzle.h b/src/sksl/ir/SkSLSwizzle.h index 3428f287fa..59ff04cb8e 100644 --- a/src/sksl/ir/SkSLSwizzle.h +++ b/src/sksl/ir/SkSLSwizzle.h @@ -136,6 +136,10 @@ struct Swizzle : public Expression { return fBase->hasProperty(property); } + int nodeCount() const override { + return 1 + fBase->nodeCount(); + } + std::unique_ptr clone() const override { return std::unique_ptr(new Swizzle(fType, fBase->clone(), fComponents)); } diff --git a/src/sksl/ir/SkSLSymbol.h b/src/sksl/ir/SkSLSymbol.h index 4ee4d3d90d..df606b88c4 100644 --- a/src/sksl/ir/SkSLSymbol.h +++ b/src/sksl/ir/SkSLSymbol.h @@ -30,7 +30,7 @@ struct Symbol : public IRNode { , fKind(kind) , fName(name) {} - virtual ~Symbol() {} + virtual ~Symbol() override {} Kind fKind; StringFragment fName; diff --git a/src/sksl/ir/SkSLSymbolTable.cpp b/src/sksl/ir/SkSLSymbolTable.cpp index bbf001d110..b0a2a56e08 100644 --- a/src/sksl/ir/SkSLSymbolTable.cpp +++ b/src/sksl/ir/SkSLSymbolTable.cpp @@ -72,6 +72,12 @@ IRNode* SymbolTable::takeOwnership(std::unique_ptr n) { return result; } +String* SymbolTable::takeOwnership(std::unique_ptr n) { + String* result = n.get(); + fOwnedStrings.push_back(std::move(n)); + return result; +} + void SymbolTable::add(StringFragment name, std::unique_ptr symbol) { this->addWithoutOwnership(name, symbol.get()); this->takeOwnership(std::move(symbol)); diff --git a/src/sksl/ir/SkSLSymbolTable.h b/src/sksl/ir/SkSLSymbolTable.h index 6969ba5e08..a3f89e2288 100644 --- a/src/sksl/ir/SkSLSymbolTable.h +++ b/src/sksl/ir/SkSLSymbolTable.h @@ -41,6 +41,8 @@ public: IRNode* takeOwnership(std::unique_ptr n); + String* takeOwnership(std::unique_ptr n); + void markAllFunctionsBuiltin(); std::unordered_map::iterator begin(); @@ -56,6 +58,8 @@ private: std::vector> fOwnedNodes; + std::vector> fOwnedStrings; + std::unordered_map fSymbols; ErrorReporter& fErrorReporter; diff --git a/src/sksl/ir/SkSLTernaryExpression.h b/src/sksl/ir/SkSLTernaryExpression.h index 80dcb8fada..cb4c004720 100644 --- a/src/sksl/ir/SkSLTernaryExpression.h +++ b/src/sksl/ir/SkSLTernaryExpression.h @@ -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 clone() const override { return std::unique_ptr(new TernaryExpression(fOffset, fTest->clone(), fIfTrue->clone(), diff --git a/src/sksl/ir/SkSLVarDeclarations.h b/src/sksl/ir/SkSLVarDeclarations.h index 82dbd8616d..86aafdb3db 100644 --- a/src/sksl/ir/SkSLVarDeclarations.h +++ b/src/sksl/ir/SkSLVarDeclarations.h @@ -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 clone() const override { std::vector> 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 clone() const override { std::vector> 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; diff --git a/src/sksl/ir/SkSLVarDeclarationsStatement.h b/src/sksl/ir/SkSLVarDeclarationsStatement.h index 465b691936..eb7880f310 100644 --- a/src/sksl/ir/SkSLVarDeclarationsStatement.h +++ b/src/sksl/ir/SkSLVarDeclarationsStatement.h @@ -30,6 +30,10 @@ struct VarDeclarationsStatement : public Statement { return true; } + int nodeCount() const override { + return 1 + fDeclaration->nodeCount(); + } + std::unique_ptr clone() const override { std::unique_ptr cloned((VarDeclarations*) fDeclaration->clone().release()); return std::unique_ptr(new VarDeclarationsStatement(std::move(cloned))); diff --git a/src/sksl/ir/SkSLVariableReference.h b/src/sksl/ir/SkSLVariableReference.h index 5d962b9ff2..c6751441dd 100644 --- a/src/sksl/ir/SkSLVariableReference.h +++ b/src/sksl/ir/SkSLVariableReference.h @@ -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 clone() const override { return std::unique_ptr(new VariableReference(fOffset, fVariable, fRefKind)); } diff --git a/src/sksl/ir/SkSLWhileStatement.h b/src/sksl/ir/SkSLWhileStatement.h index 8e311a090a..0782a01899 100644 --- a/src/sksl/ir/SkSLWhileStatement.h +++ b/src/sksl/ir/SkSLWhileStatement.h @@ -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 clone() const override { return std::unique_ptr(new WhileStatement(fOffset, fTest->clone(), fStatement->clone())); diff --git a/tests/SkSLErrorTest.cpp b/tests/SkSLErrorTest.cpp index 53214d2584..73e364a2bc 100644 --- a/tests/SkSLErrorTest.cpp +++ b/tests/SkSLErrorTest.cpp @@ -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"); } diff --git a/tests/SkSLFPTest.cpp b/tests/SkSLFPTest.cpp index c1de765e09..413f46e246 100644 --- a/tests/SkSLFPTest.cpp +++ b/tests/SkSLFPTest.cpp @@ -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);" }); } diff --git a/tests/SkSLGLSLTest.cpp b/tests/SkSLGLSLTest.cpp index a67ca25e94..d864726f04 100644 --- a/tests/SkSLGLSLTest.cpp +++ b/tests/SkSLGLSLTest.cpp @@ -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"