Simplify constructors at IR generation time.

This performs the same simplifications as the control-flow phase, but at
IR generation time. There's no visible difference in the tests (besides
DSL) because these aren't new optimizations; they're just happening
at a different phase of compilation.

Change-Id: I26d241167b0e690b23f8f4370339714783c8d6fd
Bug: skia:11343
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/371482
Commit-Queue: John Stiles <johnstiles@google.com>
Commit-Queue: Brian Osman <brianosman@google.com>
Auto-Submit: John Stiles <johnstiles@google.com>
Reviewed-by: Brian Osman <brianosman@google.com>
This commit is contained in:
John Stiles 2021-03-05 09:11:38 -05:00 committed by Skia Commit-Bot
parent 0404933136
commit b9e4f649b4
3 changed files with 123 additions and 111 deletions

View File

@ -892,6 +892,9 @@ void Compiler::simplifyExpression(DefinitionMap& definitions,
break;
}
case Expression::Kind::kConstructor: {
// TODO(skia:11319): this optimization logic is redundant with the optimization code
// found in SkSLConstructor.cpp.
// Find constructors embedded inside constructors and flatten them out where possible.
// - float4(float2(1, 2), 3, 4) --> float4(1, 2, 3, 4)
// - float4(w, float3(sin(x), cos(y), tan(z))) --> float4(w, sin(x), cos(y), tan(z))

View File

@ -129,6 +129,47 @@ std::unique_ptr<Expression> Constructor::MakeCompoundConstructor(const Context&
return nullptr;
}
if (context.fConfig->fSettings.fOptimize) {
// Find constructors embedded inside constructors and flatten them out where possible.
// - float4(float2(1, 2), 3, 4) --> float4(1, 2, 3, 4)
// - float4(w, float3(sin(x), cos(y), tan(z))) --> float4(w, sin(x), cos(y), tan(z))
// Inspect each constructor argument to see if it's a candidate for flattening.
// Remember matched arguments in a bitfield, "argsToOptimize".
int argsToOptimize = 0;
int currBit = 1;
for (const std::unique_ptr<Expression>& arg : args) {
if (arg->is<Constructor>()) {
Constructor& inner = arg->as<Constructor>();
if (inner.arguments().size() > 1 &&
inner.type().componentType() == type.componentType()) {
argsToOptimize |= currBit;
}
}
currBit <<= 1;
}
if (argsToOptimize) {
// We found at least one argument that could be flattened out. Re-walk the constructor
// args and flatten the candidates we found during our initial pass.
ExpressionArray flattened;
flattened.reserve_back(type.columns());
currBit = 1;
for (std::unique_ptr<Expression>& arg : args) {
if (argsToOptimize & currBit) {
Constructor& inner = arg->as<Constructor>();
for (std::unique_ptr<Expression>& innerArg : inner.arguments()) {
flattened.push_back(std::move(innerArg));
}
} else {
flattened.push_back(std::move(arg));
}
currBit <<= 1;
}
args = std::move(flattened);
}
}
return std::make_unique<Constructor>(offset, type, std::move(args));
}

View File

@ -136,15 +136,15 @@ DEF_GPUTEST_FOR_MOCK_CONTEXT(DSLFloat, r, ctxInfo) {
EXPECT_EQUAL(Float3(0.75),
"float3(0.75)");
EXPECT_EQUAL(Float3(Float2(0, 1), -2),
"float3(float2(0.0, 1.0), -2.0)");
"float3(0.0, 1.0, -2.0)");
EXPECT_EQUAL(Float3(0, 1, 2),
"float3(0.0, 1.0, 2.0)");
EXPECT_EQUAL(Float4(0),
"float4(0.0)");
EXPECT_EQUAL(Float4(Float2(0, 1), Float2(2, 3)),
"float4(float2(0.0, 1.0), float2(2.0, 3.0))");
"float4(0.0, 1.0, 2.0, 3.0)");
EXPECT_EQUAL(Float4(0, 1, Float2(2, 3)),
"float4(0.0, 1.0, float2(2.0, 3.0))");
"float4(0.0, 1.0, 2.0, 3.0)");
EXPECT_EQUAL(Float4(0, 1, 2, 3),
"float4(0.0, 1.0, 2.0, 3.0)");
@ -181,32 +181,24 @@ DEF_GPUTEST_FOR_MOCK_CONTEXT(DSLHalf, r, ctxInfo) {
REPORTER_ASSERT(r,
atof(e2.release()->description().c_str()) == std::numeric_limits<float>::min());
Expression e3 = Half2(0);
EXPECT_EQUAL(e3, "half2(0.0)");
Expression e4 = Half2(-0.5, 1);
EXPECT_EQUAL(e4, "half2(-0.5, 1.0)");
Expression e5 = Half3(0.75);
EXPECT_EQUAL(e5, "half3(0.75)");
Expression e6 = Half3(Half2(0, 1), -2);
EXPECT_EQUAL(e6, "half3(half2(0.0, 1.0), -2.0)");
Expression e7 = Half3(0, 1, 2);
EXPECT_EQUAL(e7, "half3(0.0, 1.0, 2.0)");
Expression e8 = Half4(0);
EXPECT_EQUAL(e8, "half4(0.0)");
Expression e9 = Half4(Half2(0, 1), Half2(2, 3));
EXPECT_EQUAL(e9, "half4(half2(0.0, 1.0), half2(2.0, 3.0))");
Expression e10 = Half4(0, 1, Half2(2, 3));
EXPECT_EQUAL(e10, "half4(0.0, 1.0, half2(2.0, 3.0))");
Expression e11 = Half4(0, 1, 2, 3);
EXPECT_EQUAL(e11, "half4(0.0, 1.0, 2.0, 3.0)");
EXPECT_EQUAL(Half2(0),
"half2(0.0)");
EXPECT_EQUAL(Half2(-0.5, 1),
"half2(-0.5, 1.0)");
EXPECT_EQUAL(Half3(0.75),
"half3(0.75)");
EXPECT_EQUAL(Half3(Half2(0, 1), -2),
"half3(0.0, 1.0, -2.0)");
EXPECT_EQUAL(Half3(0, 1, 2),
"half3(0.0, 1.0, 2.0)");
EXPECT_EQUAL(Half4(0),
"half4(0.0)");
EXPECT_EQUAL(Half4(Half2(0, 1), Half2(2, 3)),
"half4(0.0, 1.0, 2.0, 3.0)");
EXPECT_EQUAL(Half4(0, 1, Half2(2, 3)),
"half4(0.0, 1.0, 2.0, 3.0)");
EXPECT_EQUAL(Half4(0, 1, 2, 3),
"half4(0.0, 1.0, 2.0, 3.0)");
{
ExpectError error(r, "error: floating point value is infinite\n");
@ -233,35 +225,27 @@ DEF_GPUTEST_FOR_MOCK_CONTEXT(DSLHalf, r, ctxInfo) {
DEF_GPUTEST_FOR_MOCK_CONTEXT(DSLInt, r, ctxInfo) {
AutoDSLContext context(ctxInfo.directContext()->priv().getGpu());
Expression e1 = Int(std::numeric_limits<int32_t>::max());
EXPECT_EQUAL(e1, "2147483647");
Expression e2 = Int2(std::numeric_limits<int32_t>::min());
EXPECT_EQUAL(e2, "int2(-2147483648)");
Expression e3 = Int2(0, 1);
EXPECT_EQUAL(e3, "int2(0, 1)");
Expression e4 = Int3(0);
EXPECT_EQUAL(e4, "int3(0)");
Expression e5 = Int3(Int2(0, 1), -2);
EXPECT_EQUAL(e5, "int3(int2(0, 1), -2)");
Expression e6 = Int3(0, 1, 2);
EXPECT_EQUAL(e6, "int3(0, 1, 2)");
Expression e7 = Int4(0);
EXPECT_EQUAL(e7, "int4(0)");
Expression e8 = Int4(Int2(0, 1), Int2(2, 3));
EXPECT_EQUAL(e8, "int4(int2(0, 1), int2(2, 3))");
Expression e9 = Int4(0, 1, Int2(2, 3));
EXPECT_EQUAL(e9, "int4(0, 1, int2(2, 3))");
Expression e10 = Int4(0, 1, 2, 3);
EXPECT_EQUAL(e10, "int4(0, 1, 2, 3)");
EXPECT_EQUAL(Int(std::numeric_limits<int32_t>::max()),
"2147483647");
EXPECT_EQUAL(Int2(std::numeric_limits<int32_t>::min()),
"int2(-2147483648)");
EXPECT_EQUAL(Int2(0, 1),
"int2(0, 1)");
EXPECT_EQUAL(Int3(0),
"int3(0)");
EXPECT_EQUAL(Int3(Int2(0, 1), -2),
"int3(0, 1, -2)");
EXPECT_EQUAL(Int3(0, 1, 2),
"int3(0, 1, 2)");
EXPECT_EQUAL(Int4(0),
"int4(0)");
EXPECT_EQUAL(Int4(Int2(0, 1), Int2(2, 3)),
"int4(0, 1, 2, 3)");
EXPECT_EQUAL(Int4(0, 1, Int2(2, 3)),
"int4(0, 1, 2, 3)");
EXPECT_EQUAL(Int4(0, 1, 2, 3),
"int4(0, 1, 2, 3)");
{
ExpectError error(r, "error: invalid arguments to 'int2' constructor (expected 2 scalars,"
@ -278,35 +262,27 @@ DEF_GPUTEST_FOR_MOCK_CONTEXT(DSLInt, r, ctxInfo) {
DEF_GPUTEST_FOR_MOCK_CONTEXT(DSLShort, r, ctxInfo) {
AutoDSLContext context(ctxInfo.directContext()->priv().getGpu());
Expression e1 = Short(std::numeric_limits<int16_t>::max());
EXPECT_EQUAL(e1, "32767");
Expression e2 = Short2(std::numeric_limits<int16_t>::min());
EXPECT_EQUAL(e2, "short2(-32768)");
Expression e3 = Short2(0, 1);
EXPECT_EQUAL(e3, "short2(0, 1)");
Expression e4 = Short3(0);
EXPECT_EQUAL(e4, "short3(0)");
Expression e5 = Short3(Short2(0, 1), -2);
EXPECT_EQUAL(e5, "short3(short2(0, 1), -2)");
Expression e6 = Short3(0, 1, 2);
EXPECT_EQUAL(e6, "short3(0, 1, 2)");
Expression e7 = Short4(0);
EXPECT_EQUAL(e7, "short4(0)");
Expression e8 = Short4(Short2(0, 1), Short2(2, 3));
EXPECT_EQUAL(e8, "short4(short2(0, 1), short2(2, 3))");
Expression e9 = Short4(0, 1, Short2(2, 3));
EXPECT_EQUAL(e9, "short4(0, 1, short2(2, 3))");
Expression e10 = Short4(0, 1, 2, 3);
EXPECT_EQUAL(e10, "short4(0, 1, 2, 3)");
EXPECT_EQUAL(Short(std::numeric_limits<int16_t>::max()),
"32767");
EXPECT_EQUAL(Short2(std::numeric_limits<int16_t>::min()),
"short2(-32768)");
EXPECT_EQUAL(Short2(0, 1),
"short2(0, 1)");
EXPECT_EQUAL(Short3(0),
"short3(0)");
EXPECT_EQUAL(Short3(Short2(0, 1), -2),
"short3(0, 1, -2)");
EXPECT_EQUAL(Short3(0, 1, 2),
"short3(0, 1, 2)");
EXPECT_EQUAL(Short4(0),
"short4(0)");
EXPECT_EQUAL(Short4(Short2(0, 1), Short2(2, 3)),
"short4(0, 1, 2, 3)");
EXPECT_EQUAL(Short4(0, 1, Short2(2, 3)),
"short4(0, 1, 2, 3)");
EXPECT_EQUAL(Short4(0, 1, 2, 3),
"short4(0, 1, 2, 3)");
{
ExpectError error(r, "error: invalid arguments to 'short2' constructor (expected 2 scalars,"
@ -323,33 +299,25 @@ DEF_GPUTEST_FOR_MOCK_CONTEXT(DSLShort, r, ctxInfo) {
DEF_GPUTEST_FOR_MOCK_CONTEXT(DSLBool, r, ctxInfo) {
AutoDSLContext context(ctxInfo.directContext()->priv().getGpu());
Expression e1 = Bool2(false);
EXPECT_EQUAL(e1, "bool2(false)");
Expression e2 = Bool2(false, true);
EXPECT_EQUAL(e2, "bool2(false, true)");
Expression e3 = Bool3(false);
EXPECT_EQUAL(e3, "bool3(false)");
Expression e4 = Bool3(Bool2(false, true), false);
EXPECT_EQUAL(e4, "bool3(bool2(false, true), false)");
Expression e5 = Bool3(false, true, false);
EXPECT_EQUAL(e5, "bool3(false, true, false)");
Expression e6 = Bool4(false);
EXPECT_EQUAL(e6, "bool4(false)");
Expression e7 = Bool4(Bool2(false, true), Bool2(false, true));
EXPECT_EQUAL(e7, "bool4(bool2(false, true), "
"bool2(false, true))");
Expression e8 = Bool4(false, true, Bool2(false, true));
EXPECT_EQUAL(e8, "bool4(false, true, bool2(false, true))");
Expression e9 = Bool4(false, true, false, true);
EXPECT_EQUAL(e9, "bool4(false, true, false, true)");
EXPECT_EQUAL(Bool2(false),
"bool2(false)");
EXPECT_EQUAL(Bool2(false, true),
"bool2(false, true)");
EXPECT_EQUAL(Bool3(false),
"bool3(false)");
EXPECT_EQUAL(Bool3(Bool2(false, true), false),
"bool3(false, true, false)");
EXPECT_EQUAL(Bool3(false, true, false),
"bool3(false, true, false)");
EXPECT_EQUAL(Bool4(false),
"bool4(false)");
EXPECT_EQUAL(Bool4(Bool2(false, true), Bool2(false, true)),
"bool4(false, true, false, true)");
EXPECT_EQUAL(Bool4(false, true, Bool2(false, true)),
"bool4(false, true, false, true)");
EXPECT_EQUAL(Bool4(false, true, false, true),
"bool4(false, true, false, true)");
{
ExpectError error(r, "error: invalid arguments to 'bool2' constructor (expected 2 scalars,"