Improve constructor handling in Analysis::IsTrivialExpression.

This code was originally written before our constructor IR types were
split apart, so its treatment of constructors was pretty simplistic. The
new code handles each type of constructor separately, and makes better
decisions as a result.

Compound constructors are now only considered to be trivial when they
are compile-time constants; this causes vector<->matrix conversion
constructors to be detected as non-trivial.

Change-Id: I534fcf69f5d5f43ac705d68ae00f97fce8496c2a
Bug: skia:13378
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/546555
Commit-Queue: John Stiles <johnstiles@google.com>
Auto-Submit: John Stiles <johnstiles@google.com>
Reviewed-by: Michael Ludwig <michaelludwig@google.com>
This commit is contained in:
John Stiles 2022-06-03 14:22:31 -04:00 committed by SkCQ
parent 3e08ec878d
commit 871476a9b2
4 changed files with 59 additions and 27 deletions

View File

@ -62,11 +62,11 @@ half4 main(float2 coords) {
var = func4(half4(s.h));
var = func4(s.ah4[0].xxxy);
var = func4(colorGreen);
var = func4(half4(testMatrix2x2)); // matrix -> vector cast
mat = func2x2(half2x2(colorGreen)); // vector -> matrix cast
// These expressions are considered "non-trivial" and will be placed in a temporary variable
// when inlining occurs.
var = func4(half4(testMatrix2x2)); // matrix -> vector cast
mat = func2x2(half2x2(colorGreen)); // vector -> matrix cast
var = func1(-s.h);
var = funcb(!b);
// var = func2(as[i].h4.yw); // indexing by non-constant expressions disallowed in ES2

View File

@ -125,7 +125,7 @@ bool UpdateVariableRefKind(Expression* expr, VariableRefKind kind, ErrorReporter
*
* Trivial-ness is stackable. Somewhat large expressions can occasionally make the cut:
* - half4(myColor.a)
* - myStruct.myArrayField[7].xyz
* - myStruct.myArrayField[7].xzy
*/
bool IsTrivialExpression(const Expression& expr);

View File

@ -19,20 +19,50 @@
namespace SkSL {
bool Analysis::IsTrivialExpression(const Expression& expr) {
return expr.is<Literal>() ||
expr.is<VariableReference>() ||
(expr.is<Swizzle>() &&
IsTrivialExpression(*expr.as<Swizzle>().base())) ||
(expr.is<FieldAccess>() &&
IsTrivialExpression(*expr.as<FieldAccess>().base())) ||
(expr.isAnyConstructor() &&
expr.asAnyConstructor().argumentSpan().size() == 1 &&
IsTrivialExpression(*expr.asAnyConstructor().argumentSpan().front())) ||
(expr.isAnyConstructor() &&
expr.isConstantOrUniform()) ||
(expr.is<IndexExpression>() &&
expr.as<IndexExpression>().index()->isIntLiteral() &&
IsTrivialExpression(*expr.as<IndexExpression>().base()));
switch (expr.kind()) {
case Expression::Kind::kLiteral:
case Expression::Kind::kVariableReference:
return true;
case Expression::Kind::kSwizzle:
// All swizzles are considered to be trivial.
return IsTrivialExpression(*expr.as<Swizzle>().base());
case Expression::Kind::kFieldAccess:
// Accessing a field is trivial.
return IsTrivialExpression(*expr.as<FieldAccess>().base());
case Expression::Kind::kIndex: {
// Accessing a constant array index is trivial.
const IndexExpression& inner = expr.as<IndexExpression>();
return inner.index()->isIntLiteral() && IsTrivialExpression(*inner.base());
}
case Expression::Kind::kConstructorArray:
case Expression::Kind::kConstructorStruct:
// Only consider small arrays/structs of compile-time-constants to be trivial.
return expr.type().slotCount() <= 4 && expr.isCompileTimeConstant();
case Expression::Kind::kConstructorArrayCast:
case Expression::Kind::kConstructorMatrixResize:
// These operations require function calls in Metal, so they're never trivial.
return false;
case Expression::Kind::kConstructorCompound:
// Only compile-time-constant compound constructors are considered to be trivial.
return expr.isCompileTimeConstant();
case Expression::Kind::kConstructorCompoundCast:
case Expression::Kind::kConstructorScalarCast:
case Expression::Kind::kConstructorSplat:
case Expression::Kind::kConstructorDiagonalMatrix: {
// Single-argument constructors are trivial when their inner expression is trivial.
SkASSERT(expr.asAnyConstructor().argumentSpan().size() == 1);
const Expression& inner = *expr.asAnyConstructor().argumentSpan().front();
return IsTrivialExpression(inner);
}
default:
return false;
}
}
} // namespace SkSL

View File

@ -30,15 +30,17 @@ vec4 main() {
var = vec4(s.h) * vec4(s.h);
var = s.ah4[0].xxxy * s.ah4[0].xxxy;
var = colorGreen * colorGreen;
var = vec4(testMatrix2x2) * vec4(testMatrix2x2);
mat = mat2(colorGreen) * mat2(colorGreen)[0].x;
float _0_h = -s.h;
var = vec4(_0_h) * vec4(_0_h);
bool _1_b = !b;
var = vec4(float(_1_b), float(_1_b), float(_1_b), float(!_1_b));
vec3 _2_h3 = s.h4.yyy + s.h4.zzz;
var = _2_h3.xyzx * _2_h3.xyzx;
vec4 _3_h4 = vec4(s.h4.y, 0.0, 0.0, 1.0);
var = _3_h4 * _3_h4;
vec4 _0_h4 = vec4(testMatrix2x2);
var = _0_h4 * _0_h4;
mat2 _1_m = mat2(colorGreen);
mat = _1_m * _1_m[0].x;
float _2_h = -s.h;
var = vec4(_2_h) * vec4(_2_h);
bool _3_b = !b;
var = vec4(float(_3_b), float(_3_b), float(_3_b), float(!_3_b));
vec3 _4_h3 = s.h4.yyy + s.h4.zzz;
var = _4_h3.xyzx * _4_h3.xyzx;
vec4 _5_h4 = vec4(s.h4.y, 0.0, 0.0, 1.0);
var = _5_h4 * _5_h4;
return colorGreen;
}