Optimize away same-value ternaries.

A ternary of the form `anything ? value : value` can be reduced to a
comma-expression of the form `anything, value`. This seems like a rare
case in real code, but it's easy enough to detect with our existing
toolbox.

The `anything` test-expression will be eliminated from the expression
if it has no side effects, using our existing constant-folding rules
for the comma expression.

Change-Id: I1285b04cd6a08f1bed614aa1aa6f37ea2447de91
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/528439
Auto-Submit: John Stiles <johnstiles@google.com>
Reviewed-by: Brian Osman <brianosman@google.com>
Commit-Queue: John Stiles <johnstiles@google.com>
This commit is contained in:
John Stiles 2022-04-07 14:36:09 -04:00 committed by SkCQ
parent b617bced6e
commit 8397365524
6 changed files with 64 additions and 0 deletions

View File

@ -538,6 +538,7 @@ sksl_folding_tests = [
"/sksl/folding/ShortCircuitBoolFolding.sksl",
"/sksl/folding/SwizzleFolding.sksl",
"/sksl/folding/SwitchCaseFolding.sksl",
"/sksl/folding/TernaryFolding.sksl",
"/sksl/folding/VectorScalarFolding.sksl",
"/sksl/folding/VectorVectorFolding.sksl",
]

View File

@ -0,0 +1,29 @@
uniform half4 colorRed, colorGreen;
bool do_side_effect(out bool x) {
x = true;
return false;
}
const bool TRUE = true;
const bool FALSE = false;
half4 main(float2 coords) {
bool ok;
ok = (colorRed == colorGreen) ? true : true;
ok = ok && (colorGreen.g == 1 ? true : true);
ok = ok && (colorGreen.g == 0 ? TRUE : true);
ok = ok || (colorGreen.g == 1 ? false : false);
ok = ok || (colorGreen.g == 0 ? false : FALSE);
half4 green = coords.x == coords.y ? colorGreen : colorGreen;
half4 red = coords.x != coords.y ? colorRed : colorRed;
// Make sure side effects are honored.
bool param = false;
bool call = do_side_effect(param) ? true : true;
return (ok && param && call) ? green : red;
}

View File

@ -999,10 +999,12 @@ generated_cc_atom(
srcs = ["SkSLTernaryExpression.cpp"],
visibility = ["//:__subpackages__"],
deps = [
":SkSLBinaryExpression_hdr",
":SkSLLiteral_hdr",
":SkSLTernaryExpression_hdr",
"//include/sksl:SkSLErrorReporter_hdr",
"//include/sksl:SkSLOperator_hdr",
"//src/sksl:SkSLAnalysis_hdr",
"//src/sksl:SkSLConstantFolder_hdr",
"//src/sksl:SkSLContext_hdr",
"//src/sksl:SkSLProgramSettings_hdr",

View File

@ -9,9 +9,11 @@
#include "include/sksl/SkSLErrorReporter.h"
#include "include/sksl/SkSLOperator.h"
#include "src/sksl/SkSLAnalysis.h"
#include "src/sksl/SkSLConstantFolder.h"
#include "src/sksl/SkSLContext.h"
#include "src/sksl/SkSLProgramSettings.h"
#include "src/sksl/ir/SkSLBinaryExpression.h"
#include "src/sksl/ir/SkSLLiteral.h"
namespace SkSL {
@ -80,6 +82,18 @@ std::unique_ptr<Expression> TernaryExpression::Make(const Context& context,
}
}
// A ternary with matching true- and false-cases can be reduced to `(test, ifTrue)`.
// If `test` has no side-effects, it will be optimized away by the constant-folder as well.
if (context.fConfig->fSettings.fOptimize) {
const Expression* ifTrueExpr = ConstantFolder::GetConstantValueForVariable(*ifTrue);
const Expression* ifFalseExpr = ConstantFolder::GetConstantValueForVariable(*ifFalse);
if (Analysis::IsSameExpressionTree(*ifTrueExpr, *ifFalseExpr)) {
return BinaryExpression::Make(context, pos, std::move(test),
Operator::Kind::COMMA, std::move(ifTrue));
}
}
return std::make_unique<TernaryExpression>(pos, std::move(test), std::move(ifTrue),
std::move(ifFalse));
}

View File

@ -352,6 +352,7 @@ SKSL_TEST(CPU + GPU + SkQP, SelfAssignment, "folding/SelfAssign
SKSL_TEST(CPU + GPU + SkQP, ShortCircuitBoolFolding, "folding/ShortCircuitBoolFolding.sksl")
SKSL_TEST(CPU + GPU + SkQP, SwitchCaseFolding, "folding/SwitchCaseFolding.sksl")
SKSL_TEST(CPU + GPU + SkQP, SwizzleFolding, "folding/SwizzleFolding.sksl")
SKSL_TEST(CPU + GPU + SkQP, TernaryFolding, "folding/TernaryFolding.sksl")
SKSL_TEST(CPU + GPU + SkQP, VectorScalarFolding, "folding/VectorScalarFolding.sksl")
SKSL_TEST(CPU + GPU + SkQP, VectorVectorFolding, "folding/VectorVectorFolding.sksl")

View File

@ -0,0 +1,17 @@
out vec4 sk_FragColor;
uniform vec4 colorRed;
uniform vec4 colorGreen;
bool do_side_effect_bb(out bool x) {
x = true;
return false;
}
vec4 main() {
bool ok;
ok = true;
vec4 green = colorGreen;
vec4 red = colorRed;
bool param = false;
bool call = (do_side_effect_bb(param), true);
return (ok && param) && call ? green : red;
}