diff --git a/src/sksl/ir/SkSLFunctionCall.cpp b/src/sksl/ir/SkSLFunctionCall.cpp index 22e45fb1d0..a774285604 100644 --- a/src/sksl/ir/SkSLFunctionCall.cpp +++ b/src/sksl/ir/SkSLFunctionCall.cpp @@ -30,12 +30,55 @@ static bool has_compile_time_constant_arguments(const ExpressionArray& arguments return true; } +static double as_double(const Expression* expr) { + if (expr) { + if (expr->is()) { + return (double)expr->as().value(); + } + if (expr->is()) { + return (double)expr->as().value(); + } + if (expr->is()) { + return (double)expr->as().value(); + } + SkDEBUGFAILF("unexpected expression kind %d", (int)expr->kind()); + } + return 0.0; +} + template +static void type_check_expression(const Expression& expr); + +template <> +void type_check_expression(const Expression& expr) { + SkASSERT(expr.type().componentType().isFloat()); +} + +template <> +[[maybe_unused]] void type_check_expression(const Expression& expr) { + SkASSERT(expr.type().componentType().isInteger()); +} + +template <> +void type_check_expression(const Expression& expr) { + SkASSERT(expr.type().componentType().isBoolean()); +} + +template +static std::unique_ptr make_literal(int offset, double value, const Type* type) { + return Literal::Make(offset, (T)value, type); +} + +using CoalesceFn = double (*)(double, double, double); +using FinalizeFn = double (*)(double); +using MakeLiteralFn = std::unique_ptr (*)(int, double, const Type*); + static std::unique_ptr coalesce_n_way_vector(const Expression* arg0, const Expression* arg1, - T startingState, - const std::function& coalesce, - const std::function& finalize) { + double startingState, + CoalesceFn coalesce, + FinalizeFn finalize, + MakeLiteralFn makeLiteral) { // Takes up to two vector or scalar arguments and coalesces them in sequence: // scalar = startingState; // scalar = coalesce(scalar, arg0.x, arg1.x); @@ -48,6 +91,8 @@ static std::unique_ptr coalesce_n_way_vector(const Expression* arg0, // of scalars and vectors, the scalars is interpreted as a vector containing the same value for // every component. + int offset = arg0->fOffset; + arg0 = ConstantFolder::GetConstantValueForVariable(*arg0); SkASSERT(arg0); @@ -62,7 +107,7 @@ static std::unique_ptr coalesce_n_way_vector(const Expression* arg0, SkASSERT(arg1->type().componentType() == vecType.componentType()); } - T value = startingState; + double value = startingState; int arg0Index = 0; int arg1Index = 0; for (int index = 0; index < vecType.columns(); ++index) { @@ -77,15 +122,11 @@ static std::unique_ptr coalesce_n_way_vector(const Expression* arg0, SkASSERT(arg1Subexpr); } - value = coalesce(value, - arg0Subexpr->as>().value(), - arg1Subexpr ? arg1Subexpr->as>().value() : T{}); + value = coalesce(value, as_double(arg0Subexpr), as_double(arg1Subexpr)); - if constexpr (std::is_floating_point::value) { - // If coalescing the intrinsic yields a non-finite value, do not optimize. - if (!std::isfinite(value)) { - return nullptr; - } + // If coalescing the intrinsic yields a non-finite value, do not optimize. + if (!std::isfinite(value)) { + return nullptr; } } @@ -93,43 +134,32 @@ static std::unique_ptr coalesce_n_way_vector(const Expression* arg0, value = finalize(value); } - return Literal::Make(arg0->fOffset, value, &vecType.componentType()); + return makeLiteral(offset, value, &arg0->type().componentType()); } template static std::unique_ptr coalesce_vector(const ExpressionArray& arguments, - T startingState, - const std::function& coalesce, - const std::function& finalize) { + double startingState, + CoalesceFn coalesce, + FinalizeFn finalize) { SkASSERT(arguments.size() == 1); - if constexpr (std::is_same::value) { - SkASSERT(arguments.front()->type().componentType().isBoolean()); - } - if constexpr (std::is_same::value) { - SkASSERT(arguments.front()->type().componentType().isFloat()); - } + type_check_expression(*arguments[0]); - return coalesce_n_way_vector(arguments.front().get(), /*arg1=*/nullptr, startingState, - [&coalesce](T a, T b, T) { return coalesce(a, b); }, - finalize); + return coalesce_n_way_vector(arguments[0].get(), /*arg1=*/nullptr, + (double)startingState, coalesce, finalize, make_literal); } template -static std::unique_ptr coalesce_pairwise_vectors( - const ExpressionArray& arguments, - T startingState, - const std::function& coalesce, - const std::function& finalize) { +static std::unique_ptr coalesce_pairwise_vectors(const ExpressionArray& arguments, + double startingState, + CoalesceFn coalesce, + FinalizeFn finalize) { SkASSERT(arguments.size() == 2); - const Type& type = arguments.front()->type().componentType(); + type_check_expression(*arguments[0]); + type_check_expression(*arguments[1]); - if (type.isFloat()) { - return coalesce_n_way_vector(arguments[0].get(), arguments[1].get(), startingState, - coalesce, finalize); - } - - SkDEBUGFAILF("unsupported type %s", type.description().c_str()); - return nullptr; + return coalesce_n_way_vector(arguments[0].get(), arguments[1].get(), + (double)startingState, coalesce, finalize, make_literal); } template @@ -339,6 +369,21 @@ static std::unique_ptr evaluate_3_way_intrinsic(const Context& conte return nullptr; } +// Helper functions for optimizing all of our intrinsics. +namespace Intrinsics { + +double coalesce_length(double a, double b, double) { return a + (b * b); } +double finalize_length(double a) { return std::sqrt(a); } + +double coalesce_distance(double a, double b, double c) { b -= c; return a + (b * b); } +double finalize_distance(double a) { return std::sqrt(a); } + +double coalesce_dot(double a, double b, double c) { return a + (b * c); } +double coalesce_any(double a, double b, double) { return a || b; } +double coalesce_all(double a, double b, double) { return a && b; } + +} + static std::unique_ptr optimize_intrinsic_call(const Context& context, IntrinsicKind intrinsic, const ExpressionArray& arguments) { @@ -466,18 +511,16 @@ static std::unique_ptr optimize_intrinsic_call(const Context& contex // 8.4 : Geometric Functions case k_length_IntrinsicKind: return coalesce_vector(arguments, /*startingState=*/0, - [](float a, float b) { return a + (b * b); }, - [](float a) { return std::sqrt(a); }); + Intrinsics::coalesce_length, + Intrinsics::finalize_length); case k_distance_IntrinsicKind: - return coalesce_pairwise_vectors( - arguments, /*startingState=*/0, - [](float a, float b, float c) { b -= c; return a + (b * b); }, - [](float a) { return std::sqrt(a); }); + return coalesce_pairwise_vectors(arguments, /*startingState=*/0, + Intrinsics::coalesce_distance, + Intrinsics::finalize_distance); case k_dot_IntrinsicKind: - return coalesce_pairwise_vectors( - arguments, /*startingState=*/0, - [](float a, float b, float c) { return a + (b * c); }, - /*finalize=*/nullptr); + return coalesce_pairwise_vectors(arguments, /*startingState=*/0, + Intrinsics::coalesce_dot, + /*finalize=*/nullptr); case k_cross_IntrinsicKind: { auto Value = [&](int a, int n) -> float { return arguments[a]->getConstantSubexpression(n)->as().value(); @@ -596,11 +639,11 @@ static std::unique_ptr optimize_intrinsic_call(const Context& contex case k_any_IntrinsicKind: return coalesce_vector(arguments, /*startingState=*/false, - [](bool a, bool b) { return a || b; }, + Intrinsics::coalesce_any, /*finalize=*/nullptr); case k_all_IntrinsicKind: return coalesce_vector(arguments, /*startingState=*/true, - [](bool a, bool b) { return a && b; }, + Intrinsics::coalesce_all, /*finalize=*/nullptr); case k_not_IntrinsicKind: return evaluate_intrinsic(context, arguments, [](bool a) { return !a; });