Implement boolean short circuit folding in SkSL
Bug: skia: Change-Id: I0bb0506bbe6973c004ced22648588d82d2bac497 Reviewed-on: https://skia-review.googlesource.com/151820 Reviewed-by: Ethan Nicholas <ethannicholas@google.com> Commit-Queue: Michael Ludwig <michaelludwig@google.com>
This commit is contained in:
parent
0b80e62a14
commit
7b429aed84
@ -1286,9 +1286,40 @@ static bool determine_binary_type(const Context& context,
|
||||
return false;
|
||||
}
|
||||
|
||||
static std::unique_ptr<Expression> short_circuit_boolean(const Context& context,
|
||||
const Expression& left,
|
||||
Token::Kind op,
|
||||
const Expression& right) {
|
||||
SkASSERT(left.fKind == Expression::kBoolLiteral_Kind);
|
||||
bool leftVal = ((BoolLiteral&) left).fValue;
|
||||
if (op == Token::LOGICALAND) {
|
||||
// (true && expr) -> (expr) and (false && expr) -> (false)
|
||||
return leftVal ? right.clone()
|
||||
: std::unique_ptr<Expression>(new BoolLiteral(context, left.fOffset, false));
|
||||
} else if (op == Token::LOGICALOR) {
|
||||
// (true || expr) -> (true) and (false || expr) -> (expr)
|
||||
return leftVal ? std::unique_ptr<Expression>(new BoolLiteral(context, left.fOffset, true))
|
||||
: right.clone();
|
||||
} else {
|
||||
// Can't short circuit XOR
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<Expression> IRGenerator::constantFold(const Expression& left,
|
||||
Token::Kind op,
|
||||
const Expression& right) const {
|
||||
// If the left side is a constant boolean literal, the right side does not need to be constant
|
||||
// for short circuit optimizations to allow the constant to be folded.
|
||||
if (left.fKind == Expression::kBoolLiteral_Kind && !right.isConstant()) {
|
||||
return short_circuit_boolean(fContext, left, op, right);
|
||||
} else if (right.fKind == Expression::kBoolLiteral_Kind && !left.isConstant()) {
|
||||
// There aren't side effects in SKSL within expressions, so (left OP right) is equivalent to
|
||||
// (right OP left) for short-circuit optimizations
|
||||
return short_circuit_boolean(fContext, right, op, left);
|
||||
}
|
||||
|
||||
// Other than the short-circuit cases above, constant folding requires both sides to be constant
|
||||
if (!left.isConstant() || !right.isConstant()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -152,7 +152,7 @@ DEF_TEST(SkSLOperators, r) {
|
||||
" x = -6.0;\n"
|
||||
" y = -1.0;\n"
|
||||
" z = 8;\n"
|
||||
" bool b = false == true || 2.0 >= sqrt(2.0) && true;\n"
|
||||
" bool b = false == true || 2.0 >= sqrt(2.0);\n"
|
||||
" x += 12.0;\n"
|
||||
" x -= 12.0;\n"
|
||||
" x *= (y /= float(z = 10));\n"
|
||||
@ -748,6 +748,58 @@ DEF_TEST(SkSLBoolFolding, r) {
|
||||
"}\n");
|
||||
}
|
||||
|
||||
DEF_TEST(SkSLShortCircuitBoolFolding, r) {
|
||||
test(r,
|
||||
"void main() {"
|
||||
"bool expr1 = sk_FragCoord.x > 0;"
|
||||
"bool expr2 = sk_FragCoord.y > 0;"
|
||||
" if (true && expr1) {" // -> if (expr1)
|
||||
" sk_FragColor.r = 1;"
|
||||
" } else if (false && expr1) {" // -> if (false) -> block removed
|
||||
" sk_FragColor.r = -2;"
|
||||
" } else if (false || expr2) {" // -> if (expr2)
|
||||
" sk_FragColor.r = 3;"
|
||||
" } else if (true || expr2) {" // -> if (true) -> replaces unreachable else
|
||||
" sk_FragColor.r = 4;"
|
||||
" } else {" // removed
|
||||
" sk_FragColor.r = -5;"
|
||||
" }"
|
||||
// Test short-circuiting of right hand side boolean literals
|
||||
" if (expr1 && true) {" // -> if (expr1)
|
||||
" sk_FragColor.r = 1;"
|
||||
" } else if (expr1 && false) {" // -> if (false) -> block removed
|
||||
" sk_FragColor.r = -2;"
|
||||
" } else if (expr2 || false) {" // -> if (expr2)
|
||||
" sk_FragColor.r = 3;"
|
||||
" } else if (expr2 || true) {" // -> if (true) -> replaces unreachable else
|
||||
" sk_FragColor.r = 4;"
|
||||
" } else {" // removed
|
||||
" sk_FragColor.r = -5;"
|
||||
" }"
|
||||
"}",
|
||||
*SkSL::ShaderCapsFactory::Default(),
|
||||
"#version 400\n"
|
||||
"out vec4 sk_FragColor;\n"
|
||||
"void main() {\n"
|
||||
" bool expr1 = gl_FragCoord.x > 0.0;\n"
|
||||
" bool expr2 = gl_FragCoord.y > 0.0;\n"
|
||||
" if (expr1) {\n"
|
||||
" sk_FragColor.x = 1.0;\n"
|
||||
" } else if (expr2) {\n"
|
||||
" sk_FragColor.x = 3.0;\n"
|
||||
" } else {\n"
|
||||
" sk_FragColor.x = 4.0;\n"
|
||||
" }\n"
|
||||
" if (expr1) {\n"
|
||||
" sk_FragColor.x = 1.0;\n"
|
||||
" } else if (expr2) {\n"
|
||||
" sk_FragColor.x = 3.0;\n"
|
||||
" } else {\n"
|
||||
" sk_FragColor.x = 4.0;\n"
|
||||
" }\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
DEF_TEST(SkSLVecFolding, r) {
|
||||
test(r,
|
||||
"void main() {"
|
||||
|
Loading…
Reference in New Issue
Block a user