Added support for the 'inline' hint on SkSL functions

Change-Id: Ib78e0ad9fd1cc15e7afeb2a9ddd6b1249828fbe7
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/311603
Commit-Queue: Ethan Nicholas <ethannicholas@google.com>
Reviewed-by: John Stiles <johnstiles@google.com>
This commit is contained in:
Ethan Nicholas 2020-08-19 11:01:00 -04:00 committed by Skia Commit-Bot
parent 7f1117e886
commit 338e57d4b1
11 changed files with 871 additions and 755 deletions

View File

@ -63,6 +63,8 @@ Differences from GLSL
* All texture functions are named "sample", e.g. sample(sampler2D, float3) is
equivalent to GLSL's textureProj(sampler2D, float3).
* Render target width and height are available via sk_Width and sk_Height
* Functions support the 'inline' modifier, which causes the compiler to ignore
its normal inlining heuristics and inline the function if at all possible
* some built-in functions and one or two rarely-used language features are not
yet supported (sorry!)

View File

@ -874,6 +874,7 @@ void IRGenerator::checkModifiers(int offset, const Modifiers& modifiers, int per
CHECK(Modifiers::kPLSIn_Flag, "__pixel_local_inEXT")
CHECK(Modifiers::kPLSOut_Flag, "__pixel_local_outEXT")
CHECK(Modifiers::kVarying_Flag, "varying")
CHECK(Modifiers::kInline_Flag, "inline")
SkASSERT(flags == 0);
}
@ -900,7 +901,8 @@ void IRGenerator::convertFunction(const ASTNode& f) {
return;
}
const ASTNode::FunctionData& fd = f.getFunctionData();
this->checkModifiers(f.fOffset, fd.fModifiers, Modifiers::kHasSideEffects_Flag);
this->checkModifiers(f.fOffset, fd.fModifiers, Modifiers::kHasSideEffects_Flag |
Modifiers::kInline_Flag);
std::vector<const Variable*> parameters;
for (size_t i = 0; i < fd.fParameterCount; ++i) {
const ASTNode& param = *(iter++);
@ -2390,8 +2392,9 @@ bool IRGenerator::isSafeToInline(const FunctionDefinition& functionDef) {
// Inlining has been explicitly disabled by the IR generator.
return false;
}
if (functionDef.inlinedFunctionSize() >= fSettings->fInlineThreshold) {
// The function exceeds our maximum inline size.
if (!(functionDef.fDeclaration.fModifiers.fFlags & Modifiers::kInline_Flag) &&
functionDef.inlinedFunctionSize() >= fSettings->fInlineThreshold) {
// The function exceeds our maximum inline size and is not flagged 'inline'.
return false;
}
if (!fSettings->fCaps || !fSettings->fCaps->canUseDoLoops()) {

File diff suppressed because it is too large Load Diff

View File

@ -48,6 +48,7 @@ struct Token {
TK_VOLATILE,
TK_RESTRICT,
TK_BUFFER,
TK_INLINE,
TK_HASSIDEEFFECTS,
TK_PLS,
TK_PLSIN,

View File

@ -936,7 +936,7 @@ Layout Parser::layout() {
/* layout? (UNIFORM | CONST | IN | OUT | INOUT | LOWP | MEDIUMP | HIGHP | FLAT | NOPERSPECTIVE |
READONLY | WRITEONLY | COHERENT | VOLATILE | RESTRICT | BUFFER | PLS | PLSIN |
PLSOUT | VARYING)* */
PLSOUT | VARYING | INLINE)* */
Modifiers Parser::modifiers() {
Layout layout = this->layout();
int flags = 0;
@ -1016,6 +1016,10 @@ Modifiers Parser::modifiers() {
this->nextToken();
flags |= Modifiers::kVarying_Flag;
break;
case Token::Kind::TK_INLINE:
this->nextToken();
flags |= Modifiers::kInline_Flag;
break;
default:
return Modifiers(layout, flags);
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -35,6 +35,7 @@ struct Modifiers {
kPLSIn_Flag = 1 << 14,
kPLSOut_Flag = 1 << 15,
kVarying_Flag = 1 << 16,
kInline_Flag = 1 << 17,
};
Modifiers()

View File

@ -178,6 +178,12 @@ void process(const char* inPath, const char* lexer, const char* token, const cha
std::string line;
std::ifstream in(inPath);
while (std::getline(in, line)) {
if (line.length() == 0) {
continue;
}
if (line.length() >= 2 && line[0] == '/' && line[1] == '/') {
continue;
}
std::istringstream split(line);
std::string name, delimiter, pattern;
if (split >> name >> delimiter >> pattern) {

View File

@ -1,3 +1,14 @@
// *****************
// *** IMPORTANT ***
// *****************
//
// 1. This file is only used when gn arg sksl_lex is set to true. It is used to regenerate the
// SkSLLexer.h and SkSLLexer.cpp files.
// 2. Since token IDs are used to identify operators and baked into the .dehydrated.sksl files,
// after modifying this file it is likely everything will break until you update the dehydrated
// binaries. If things break after updating the lexer, set REHYDRATE in SkSLCompiler.cpp to 0,
// rebuild, and then set it back to 1.
FLOAT_LITERAL = [0-9]*\.[0-9]+([eE][+-]?[0-9]+)?|[0-9]+\.[0-9]*([eE][+-]?[0-9]+)?|[0-9]+([eE][+-]?[0-9]+)
INT_LITERAL = [0-9]+|0x[0-9a-fA-F]+
TRUE_LITERAL = "true"
@ -30,6 +41,7 @@ COHERENT = "coherent"
VOLATILE = "volatile"
RESTRICT = "restrict"
BUFFER = "buffer"
INLINE = "inline"
HASSIDEEFFECTS = "sk_has_side_effects"
PLS = "__pixel_localEXT"
PLSIN = "__pixel_local_inEXT"

View File

@ -126,6 +126,83 @@ DEF_TEST(SkSLFunctions, r) {
"}\n");
}
DEF_TEST(SkSLFunctionInlineThreshold, r) {
test(r,
"void tooBig(inout int x) {"
" ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x;"
" ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x;"
"}"
"void main() { int x = 0; tooBig(x); }",
*SkSL::ShaderCapsFactory::Default(),
"#version 400\n"
"void tooBig(inout int x) {\n"
" ++x;\n ++x;\n ++x;\n ++x;\n ++x;\n ++x;\n ++x;\n ++x;\n"
" ++x;\n ++x;\n ++x;\n ++x;\n ++x;\n ++x;\n ++x;\n ++x;\n"
" ++x;\n ++x;\n ++x;\n ++x;\n ++x;\n ++x;\n ++x;\n ++x;\n"
" ++x;\n ++x;\n ++x;\n ++x;\n ++x;\n ++x;\n ++x;\n ++x;\n"
" ++x;\n ++x;\n"
"}\n"
"void main() {\n"
" int x = 0;\n"
" tooBig(x);\n"
"}\n"
);
test(r,
"inline void tooBig(inout int x) {"
" ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x;"
" ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x;"
"}"
"void main() { int x = 0; tooBig(x); }",
*SkSL::ShaderCapsFactory::Default(),
"#version 400\n"
"void main() {\n"
" int x = 0;\n"
" int _inlineArgvoidtooBigint0_0 = x;\n"
" {\n"
" ++_inlineArgvoidtooBigint0_0;\n ++_inlineArgvoidtooBigint0_0;\n"
" ++_inlineArgvoidtooBigint0_0;\n ++_inlineArgvoidtooBigint0_0;\n"
" ++_inlineArgvoidtooBigint0_0;\n ++_inlineArgvoidtooBigint0_0;\n"
" ++_inlineArgvoidtooBigint0_0;\n ++_inlineArgvoidtooBigint0_0;\n"
" ++_inlineArgvoidtooBigint0_0;\n ++_inlineArgvoidtooBigint0_0;\n"
" ++_inlineArgvoidtooBigint0_0;\n ++_inlineArgvoidtooBigint0_0;\n"
" ++_inlineArgvoidtooBigint0_0;\n ++_inlineArgvoidtooBigint0_0;\n"
" ++_inlineArgvoidtooBigint0_0;\n ++_inlineArgvoidtooBigint0_0;\n"
" ++_inlineArgvoidtooBigint0_0;\n ++_inlineArgvoidtooBigint0_0;\n"
" ++_inlineArgvoidtooBigint0_0;\n ++_inlineArgvoidtooBigint0_0;\n"
" ++_inlineArgvoidtooBigint0_0;\n ++_inlineArgvoidtooBigint0_0;\n"
" ++_inlineArgvoidtooBigint0_0;\n ++_inlineArgvoidtooBigint0_0;\n"
" ++_inlineArgvoidtooBigint0_0;\n ++_inlineArgvoidtooBigint0_0;\n"
" ++_inlineArgvoidtooBigint0_0;\n ++_inlineArgvoidtooBigint0_0;\n"
" ++_inlineArgvoidtooBigint0_0;\n ++_inlineArgvoidtooBigint0_0;\n"
" ++_inlineArgvoidtooBigint0_0;\n ++_inlineArgvoidtooBigint0_0;\n"
" ++_inlineArgvoidtooBigint0_0;\n ++_inlineArgvoidtooBigint0_0;\n"
" }\n"
" x = _inlineArgvoidtooBigint0_0;\n"
"\n"
"}\n"
);
test(r,
"inline void cantActuallyInline(inout int x) {"
" for (;;) {"
" ++x;"
" if (x > 10) return;"
" }"
"}"
"void main() { int x = 0; cantActuallyInline(x); }",
*SkSL::ShaderCapsFactory::Default(),
"#version 400\n"
"void cantActuallyInline(inout int x) {\n"
" for (; ; ) {\n"
" ++x;\n"
" if (x > 10) return;\n"
" }\n"
"}\n"
"void main() {\n"
" int x = 0;\n"
" cantActuallyInline(x);\n"
"}\n");
}
DEF_TEST(SkSLOperators, r) {
test(r,
"void main() {"