• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2021 Google LLC
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "src/sksl/SkSLAnalysis.h"
9 #include "src/sksl/SkSLConstantFolder.h"
10 #include "src/sksl/SkSLContext.h"
11 #include "src/sksl/SkSLProgramSettings.h"
12 #include "src/sksl/dsl/priv/DSLWriter.h"
13 #include "src/sksl/ir/SkSLChildCall.h"
14 #include "src/sksl/ir/SkSLConstructorCompound.h"
15 #include "src/sksl/ir/SkSLExternalFunctionCall.h"
16 #include "src/sksl/ir/SkSLExternalFunctionReference.h"
17 #include "src/sksl/ir/SkSLFunctionCall.h"
18 #include "src/sksl/ir/SkSLFunctionReference.h"
19 #include "src/sksl/ir/SkSLLiteral.h"
20 #include "src/sksl/ir/SkSLMethodReference.h"
21 #include "src/sksl/ir/SkSLTypeReference.h"
22 
23 #include "include/private/SkFloatingPoint.h"
24 #include "include/sksl/DSLCore.h"
25 #include "src/core/SkMatrixInvert.h"
26 
27 #include <array>
28 
29 namespace SkSL {
30 
31 using IntrinsicArguments = std::array<const Expression*, 3>;
32 
has_compile_time_constant_arguments(const ExpressionArray & arguments)33 static bool has_compile_time_constant_arguments(const ExpressionArray& arguments) {
34     for (const std::unique_ptr<Expression>& arg : arguments) {
35         const Expression* expr = ConstantFolder::GetConstantValueForVariable(*arg);
36         if (!expr->isCompileTimeConstant()) {
37             return false;
38         }
39     }
40     return true;
41 }
42 
43 template <typename T>
44 static void type_check_expression(const Expression& expr);
45 
46 template <>
type_check_expression(const Expression & expr)47 void type_check_expression<float>(const Expression& expr) {
48     SkASSERT(expr.type().componentType().isFloat());
49 }
50 
51 template <>
type_check_expression(const Expression & expr)52 void type_check_expression<SKSL_INT>(const Expression& expr) {
53     SkASSERT(expr.type().componentType().isInteger());
54 }
55 
56 template <>
type_check_expression(const Expression & expr)57 void type_check_expression<bool>(const Expression& expr) {
58     SkASSERT(expr.type().componentType().isBoolean());
59 }
60 
assemble_compound(const Context & context,int line,const Type & returnType,double value[])61 static std::unique_ptr<Expression> assemble_compound(const Context& context,
62                                                      int line,
63                                                      const Type& returnType,
64                                                      double value[]) {
65     int numSlots = returnType.slotCount();
66     ExpressionArray array;
67     array.reserve_back(numSlots);
68     for (int index = 0; index < numSlots; ++index) {
69         array.push_back(Literal::Make(line, value[index], &returnType.componentType()));
70     }
71     return ConstructorCompound::Make(context, line, returnType, std::move(array));
72 }
73 
74 using CoalesceFn = double (*)(double, double, double);
75 using FinalizeFn = double (*)(double);
76 
coalesce_n_way_vector(const Expression * arg0,const Expression * arg1,double startingState,const Type & returnType,CoalesceFn coalesce,FinalizeFn finalize)77 static std::unique_ptr<Expression> coalesce_n_way_vector(const Expression* arg0,
78                                                          const Expression* arg1,
79                                                          double startingState,
80                                                          const Type& returnType,
81                                                          CoalesceFn coalesce,
82                                                          FinalizeFn finalize) {
83     // Takes up to two vector or scalar arguments and coalesces them in sequence:
84     //     scalar = startingState;
85     //     scalar = coalesce(scalar, arg0.x, arg1.x);
86     //     scalar = coalesce(scalar, arg0.y, arg1.y);
87     //     scalar = coalesce(scalar, arg0.z, arg1.z);
88     //     scalar = coalesce(scalar, arg0.w, arg1.w);
89     //     scalar = finalize(scalar);
90     //
91     // If an argument is null, zero is passed to the coalesce function. If the arguments are a mix
92     // of scalars and vectors, the scalars is interpreted as a vector containing the same value for
93     // every component.
94 
95     int line = arg0->fLine;
96 
97     const Type& vecType =          arg0->type().isVector()  ? arg0->type() :
98                           (arg1 && arg1->type().isVector()) ? arg1->type() :
99                                                               arg0->type();
100     SkASSERT(         arg0->type().componentType() == vecType.componentType());
101     SkASSERT(!arg1 || arg1->type().componentType() == vecType.componentType());
102 
103     double value = startingState;
104     int arg0Index = 0;
105     int arg1Index = 0;
106     for (int index = 0; index < vecType.columns(); ++index) {
107         skstd::optional<double> arg0Value = arg0->getConstantValue(arg0Index);
108         arg0Index += arg0->type().isVector() ? 1 : 0;
109         SkASSERT(arg0Value.has_value());
110 
111         skstd::optional<double> arg1Value = 0.0;
112         if (arg1) {
113             arg1Value = arg1->getConstantValue(arg1Index);
114             arg1Index += arg1->type().isVector() ? 1 : 0;
115             SkASSERT(arg1Value.has_value());
116         }
117 
118         value = coalesce(value, *arg0Value, *arg1Value);
119 
120         // If coalescing the intrinsic yields a non-finite value, do not optimize.
121         if (!std::isfinite(value)) {
122             return nullptr;
123         }
124     }
125 
126     if (finalize) {
127         value = finalize(value);
128     }
129 
130     return Literal::Make(line, value, &returnType);
131 }
132 
133 template <typename T>
coalesce_vector(const IntrinsicArguments & arguments,double startingState,const Type & returnType,CoalesceFn coalesce,FinalizeFn finalize)134 static std::unique_ptr<Expression> coalesce_vector(const IntrinsicArguments& arguments,
135                                                    double startingState,
136                                                    const Type& returnType,
137                                                    CoalesceFn coalesce,
138                                                    FinalizeFn finalize) {
139     SkASSERT(arguments[0]);
140     SkASSERT(!arguments[1]);
141     type_check_expression<T>(*arguments[0]);
142 
143     return coalesce_n_way_vector(arguments[0], /*arg1=*/nullptr,
144                                  startingState, returnType, coalesce, finalize);
145 }
146 
147 template <typename T>
coalesce_pairwise_vectors(const IntrinsicArguments & arguments,double startingState,const Type & returnType,CoalesceFn coalesce,FinalizeFn finalize)148 static std::unique_ptr<Expression> coalesce_pairwise_vectors(const IntrinsicArguments& arguments,
149                                                              double startingState,
150                                                              const Type& returnType,
151                                                              CoalesceFn coalesce,
152                                                              FinalizeFn finalize) {
153     SkASSERT(arguments[0]);
154     SkASSERT(arguments[1]);
155     SkASSERT(!arguments[2]);
156     type_check_expression<T>(*arguments[0]);
157     type_check_expression<T>(*arguments[1]);
158 
159     return coalesce_n_way_vector(arguments[0], arguments[1],
160                                  startingState, returnType, coalesce, finalize);
161 }
162 
163 using CompareFn = bool (*)(double, double);
164 
optimize_comparison(const Context & context,const IntrinsicArguments & arguments,CompareFn compare)165 static std::unique_ptr<Expression> optimize_comparison(const Context& context,
166                                                        const IntrinsicArguments& arguments,
167                                                        CompareFn compare) {
168     const Expression* left = arguments[0];
169     const Expression* right = arguments[1];
170     SkASSERT(left);
171     SkASSERT(right);
172     SkASSERT(!arguments[2]);
173 
174     const Type& type = left->type();
175     SkASSERT(type.isVector());
176     SkASSERT(type.componentType().isScalar());
177     SkASSERT(type == right->type());
178 
179     double array[4];
180 
181     for (int index = 0; index < type.columns(); ++index) {
182         skstd::optional<double> leftValue = left->getConstantValue(index);
183         skstd::optional<double> rightValue = right->getConstantValue(index);
184         SkASSERT(leftValue.has_value());
185         SkASSERT(rightValue.has_value());
186         array[index] = compare(*leftValue, *rightValue) ? 1.0 : 0.0;
187     }
188 
189     const Type& bvecType = context.fTypes.fBool->toCompound(context, type.columns(), /*rows=*/1);
190     return assemble_compound(context, left->fLine, bvecType, array);
191 }
192 
193 using EvaluateFn = double (*)(double, double, double);
194 
evaluate_n_way_intrinsic(const Context & context,const Expression * arg0,const Expression * arg1,const Expression * arg2,const Type & returnType,EvaluateFn eval)195 static std::unique_ptr<Expression> evaluate_n_way_intrinsic(const Context& context,
196                                                             const Expression* arg0,
197                                                             const Expression* arg1,
198                                                             const Expression* arg2,
199                                                             const Type& returnType,
200                                                             EvaluateFn eval) {
201     // Takes up to three arguments and evaluates all of them, left-to-right, in tandem.
202     // Equivalent to constructing a new compound value containing the results from:
203     //     eval(arg0.x, arg1.x, arg2.x),
204     //     eval(arg0.y, arg1.y, arg2.y),
205     //     eval(arg0.z, arg1.z, arg2.z),
206     //     eval(arg0.w, arg1.w, arg2.w)
207     //
208     // If an argument is null, zero is passed to the evaluation function. If the arguments are a mix
209     // of scalars and compounds, scalars are interpreted as a compound containing the same value for
210     // every component.
211 
212     int slots = returnType.slotCount();
213     double array[16];
214 
215     int arg0Index = 0;
216     int arg1Index = 0;
217     int arg2Index = 0;
218     for (int index = 0; index < slots; ++index) {
219         skstd::optional<double> arg0Value = arg0->getConstantValue(arg0Index);
220         arg0Index += arg0->type().isScalar() ? 0 : 1;
221         SkASSERT(arg0Value.has_value());
222 
223         skstd::optional<double> arg1Value = 0.0;
224         if (arg1) {
225             arg1Value = arg1->getConstantValue(arg1Index);
226             arg1Index += arg1->type().isScalar() ? 0 : 1;
227             SkASSERT(arg1Value.has_value());
228         }
229 
230         skstd::optional<double> arg2Value = 0.0;
231         if (arg2) {
232             arg2Value = arg2->getConstantValue(arg2Index);
233             arg2Index += arg2->type().isScalar() ? 0 : 1;
234             SkASSERT(arg2Value.has_value());
235         }
236 
237         array[index] = eval(*arg0Value, *arg1Value, *arg2Value);
238 
239         // If evaluation of the intrinsic yields a non-finite value, do not optimize.
240         if (!std::isfinite(array[index])) {
241             return nullptr;
242         }
243     }
244 
245     return assemble_compound(context, arg0->fLine, returnType, array);
246 }
247 
248 template <typename T>
evaluate_intrinsic(const Context & context,const IntrinsicArguments & arguments,const Type & returnType,EvaluateFn eval)249 static std::unique_ptr<Expression> evaluate_intrinsic(const Context& context,
250                                                       const IntrinsicArguments& arguments,
251                                                       const Type& returnType,
252                                                       EvaluateFn eval) {
253     SkASSERT(arguments[0]);
254     SkASSERT(!arguments[1]);
255     type_check_expression<T>(*arguments[0]);
256 
257     return evaluate_n_way_intrinsic(context, arguments[0], /*arg1=*/nullptr, /*arg2=*/nullptr,
258                                     returnType, eval);
259 }
260 
evaluate_intrinsic_numeric(const Context & context,const IntrinsicArguments & arguments,const Type & returnType,EvaluateFn eval)261 static std::unique_ptr<Expression> evaluate_intrinsic_numeric(const Context& context,
262                                                               const IntrinsicArguments& arguments,
263                                                               const Type& returnType,
264                                                               EvaluateFn eval) {
265     SkASSERT(arguments[0]);
266     SkASSERT(!arguments[1]);
267     const Type& type = arguments[0]->type().componentType();
268 
269     if (type.isFloat()) {
270         return evaluate_intrinsic<float>(context, arguments, returnType, eval);
271     }
272     if (type.isInteger()) {
273         return evaluate_intrinsic<SKSL_INT>(context, arguments, returnType, eval);
274     }
275 
276     SkDEBUGFAILF("unsupported type %s", type.description().c_str());
277     return nullptr;
278 }
279 
evaluate_pairwise_intrinsic(const Context & context,const IntrinsicArguments & arguments,const Type & returnType,EvaluateFn eval)280 static std::unique_ptr<Expression> evaluate_pairwise_intrinsic(const Context& context,
281                                                                const IntrinsicArguments& arguments,
282                                                                const Type& returnType,
283                                                                EvaluateFn eval) {
284     SkASSERT(arguments[0]);
285     SkASSERT(arguments[1]);
286     SkASSERT(!arguments[2]);
287     const Type& type = arguments[0]->type().componentType();
288 
289     if (type.isFloat()) {
290         type_check_expression<float>(*arguments[0]);
291         type_check_expression<float>(*arguments[1]);
292     } else if (type.isInteger()) {
293         type_check_expression<SKSL_INT>(*arguments[0]);
294         type_check_expression<SKSL_INT>(*arguments[1]);
295     } else {
296         SkDEBUGFAILF("unsupported type %s", type.description().c_str());
297         return nullptr;
298     }
299 
300     return evaluate_n_way_intrinsic(context, arguments[0], arguments[1], /*arg2=*/nullptr,
301                                     returnType, eval);
302 }
303 
evaluate_3_way_intrinsic(const Context & context,const IntrinsicArguments & arguments,const Type & returnType,EvaluateFn eval)304 static std::unique_ptr<Expression> evaluate_3_way_intrinsic(const Context& context,
305                                                             const IntrinsicArguments& arguments,
306                                                             const Type& returnType,
307                                                             EvaluateFn eval) {
308     SkASSERT(arguments[0]);
309     SkASSERT(arguments[1]);
310     SkASSERT(arguments[2]);
311     const Type& type = arguments[0]->type().componentType();
312 
313     if (type.isFloat()) {
314         type_check_expression<float>(*arguments[0]);
315         type_check_expression<float>(*arguments[1]);
316         type_check_expression<float>(*arguments[2]);
317     } else if (type.isInteger()) {
318         type_check_expression<SKSL_INT>(*arguments[0]);
319         type_check_expression<SKSL_INT>(*arguments[1]);
320         type_check_expression<SKSL_INT>(*arguments[2]);
321     } else {
322         SkDEBUGFAILF("unsupported type %s", type.description().c_str());
323         return nullptr;
324     }
325 
326     return evaluate_n_way_intrinsic(context, arguments[0], arguments[1], arguments[2],
327                                     returnType, eval);
328 }
329 
330 template <typename T1, typename T2>
pun_value(double val)331 static double pun_value(double val) {
332     // Interpret `val` as a value of type T1.
333     static_assert(sizeof(T1) == sizeof(T2));
334     T1 inputValue = (T1)val;
335     // Reinterpret those bits as a value of type T2.
336     T2 outputValue;
337     memcpy(&outputValue, &inputValue, sizeof(T2));
338     // Return the value-of-type-T2 as a double. (Non-finite values will prohibit optimization.)
339     return (double)outputValue;
340 }
341 
342 // Helper functions for optimizing all of our intrinsics.
343 namespace Intrinsics {
344 namespace {
345 
coalesce_length(double a,double b,double)346 double coalesce_length(double a, double b, double)     { return a + (b * b); }
finalize_length(double a)347 double finalize_length(double a)                       { return std::sqrt(a); }
348 
coalesce_distance(double a,double b,double c)349 double coalesce_distance(double a, double b, double c) { b -= c; return a + (b * b); }
finalize_distance(double a)350 double finalize_distance(double a)                     { return std::sqrt(a); }
351 
coalesce_dot(double a,double b,double c)352 double coalesce_dot(double a, double b, double c)      { return a + (b * c); }
coalesce_any(double a,double b,double)353 double coalesce_any(double a, double b, double)        { return a || b; }
coalesce_all(double a,double b,double)354 double coalesce_all(double a, double b, double)        { return a && b; }
355 
compare_lessThan(double a,double b)356 bool compare_lessThan(double a, double b)              { return a < b; }
compare_lessThanEqual(double a,double b)357 bool compare_lessThanEqual(double a, double b)         { return a <= b; }
compare_greaterThan(double a,double b)358 bool compare_greaterThan(double a, double b)           { return a > b; }
compare_greaterThanEqual(double a,double b)359 bool compare_greaterThanEqual(double a, double b)      { return a >= b; }
compare_equal(double a,double b)360 bool compare_equal(double a, double b)                 { return a == b; }
compare_notEqual(double a,double b)361 bool compare_notEqual(double a, double b)              { return a != b; }
362 
evaluate_radians(double a,double,double)363 double evaluate_radians(double a, double, double)      { return a * 0.0174532925; }
evaluate_degrees(double a,double,double)364 double evaluate_degrees(double a, double, double)      { return a * 57.2957795; }
evaluate_sin(double a,double,double)365 double evaluate_sin(double a, double, double)          { return std::sin(a); }
evaluate_cos(double a,double,double)366 double evaluate_cos(double a, double, double)          { return std::cos(a); }
evaluate_tan(double a,double,double)367 double evaluate_tan(double a, double, double)          { return std::tan(a); }
evaluate_asin(double a,double,double)368 double evaluate_asin(double a, double, double)         { return std::asin(a); }
evaluate_acos(double a,double,double)369 double evaluate_acos(double a, double, double)         { return std::acos(a); }
evaluate_atan(double a,double,double)370 double evaluate_atan(double a, double, double)         { return std::atan(a); }
evaluate_atan2(double a,double b,double)371 double evaluate_atan2(double a, double b, double)      { return std::atan2(a, b); }
evaluate_asinh(double a,double,double)372 double evaluate_asinh(double a, double, double)        { return std::asinh(a); }
evaluate_acosh(double a,double,double)373 double evaluate_acosh(double a, double, double)        { return std::acosh(a); }
evaluate_atanh(double a,double,double)374 double evaluate_atanh(double a, double, double)        { return std::atanh(a); }
375 
evaluate_pow(double a,double b,double)376 double evaluate_pow(double a, double b, double)        { return std::pow(a, b); }
evaluate_exp(double a,double,double)377 double evaluate_exp(double a, double, double)          { return std::exp(a); }
evaluate_log(double a,double,double)378 double evaluate_log(double a, double, double)          { return std::log(a); }
evaluate_exp2(double a,double,double)379 double evaluate_exp2(double a, double, double)         { return std::exp2(a); }
evaluate_log2(double a,double,double)380 double evaluate_log2(double a, double, double)         { return std::log2(a); }
evaluate_sqrt(double a,double,double)381 double evaluate_sqrt(double a, double, double)         { return std::sqrt(a); }
evaluate_inversesqrt(double a,double,double)382 double evaluate_inversesqrt(double a, double, double) {
383     return sk_ieee_double_divide(1.0, std::sqrt(a));
384 }
385 
evaluate_abs(double a,double,double)386 double evaluate_abs(double a, double, double)          { return std::abs(a); }
evaluate_sign(double a,double,double)387 double evaluate_sign(double a, double, double)         { return (a > 0) - (a < 0); }
evaluate_floor(double a,double,double)388 double evaluate_floor(double a, double, double)        { return std::floor(a); }
evaluate_ceil(double a,double,double)389 double evaluate_ceil(double a, double, double)         { return std::ceil(a); }
evaluate_fract(double a,double,double)390 double evaluate_fract(double a, double, double)        { return a - std::floor(a); }
evaluate_min(double a,double b,double)391 double evaluate_min(double a, double b, double)        { return (a < b) ? a : b; }
evaluate_max(double a,double b,double)392 double evaluate_max(double a, double b, double)        { return (a > b) ? a : b; }
evaluate_clamp(double x,double l,double h)393 double evaluate_clamp(double x, double l, double h)    { return (x < l) ? l : (x > h) ? h : x; }
evaluate_saturate(double a,double,double)394 double evaluate_saturate(double a, double, double)     { return (a < 0) ? 0 : (a > 1) ? 1 : a; }
evaluate_mix(double x,double y,double a)395 double evaluate_mix(double x, double y, double a)      { return x * (1 - a) + y * a; }
evaluate_step(double e,double x,double)396 double evaluate_step(double e, double x, double)       { return (x < e) ? 0 : 1; }
evaluate_mod(double a,double b,double)397 double evaluate_mod(double a, double b, double) {
398     return a - b * std::floor(sk_ieee_double_divide(a, b));
399 }
evaluate_smoothstep(double edge0,double edge1,double x)400 double evaluate_smoothstep(double edge0, double edge1, double x) {
401     double t = sk_ieee_double_divide(x - edge0, edge1 - edge0);
402     t = (t < 0) ? 0 : (t > 1) ? 1 : t;
403     return t * t * (3.0 - 2.0 * t);
404 }
405 
evaluate_matrixCompMult(double x,double y,double)406 double evaluate_matrixCompMult(double x, double y, double) { return x * y; }
407 
evaluate_not(double a,double,double)408 double evaluate_not(double a, double, double)          { return !a; }
evaluate_sinh(double a,double,double)409 double evaluate_sinh(double a, double, double)         { return std::sinh(a); }
evaluate_cosh(double a,double,double)410 double evaluate_cosh(double a, double, double)         { return std::cosh(a); }
evaluate_tanh(double a,double,double)411 double evaluate_tanh(double a, double, double)         { return std::tanh(a); }
evaluate_trunc(double a,double,double)412 double evaluate_trunc(double a, double, double)        { return std::trunc(a); }
evaluate_round(double a,double,double)413 double evaluate_round(double a, double, double) {
414     // The semantics of std::remainder guarantee a rounded-to-even result here, regardless of the
415     // current float-rounding mode.
416     return a - std::remainder(a, 1.0);
417 }
evaluate_floatBitsToInt(double a,double,double)418 double evaluate_floatBitsToInt(double a, double, double)  { return pun_value<float, int32_t> (a); }
evaluate_floatBitsToUint(double a,double,double)419 double evaluate_floatBitsToUint(double a, double, double) { return pun_value<float, uint32_t>(a); }
evaluate_intBitsToFloat(double a,double,double)420 double evaluate_intBitsToFloat(double a, double, double)  { return pun_value<int32_t,  float>(a); }
evaluate_uintBitsToFloat(double a,double,double)421 double evaluate_uintBitsToFloat(double a, double, double) { return pun_value<uint32_t, float>(a); }
422 
423 }  // namespace
424 }  // namespace Intrinsics
425 
extract_matrix(const Expression * expr,float mat[16])426 static void extract_matrix(const Expression* expr, float mat[16]) {
427     size_t numSlots = expr->type().slotCount();
428     for (size_t index = 0; index < numSlots; ++index) {
429         mat[index] = *expr->getConstantValue(index);
430     }
431 }
432 
optimize_intrinsic_call(const Context & context,IntrinsicKind intrinsic,const ExpressionArray & argArray,const Type & returnType)433 static std::unique_ptr<Expression> optimize_intrinsic_call(const Context& context,
434                                                            IntrinsicKind intrinsic,
435                                                            const ExpressionArray& argArray,
436                                                            const Type& returnType) {
437     // Replace constant variables with their literal values.
438     IntrinsicArguments arguments = {};
439     SkASSERT(argArray.size() <= arguments.size());
440     for (int index = 0; index < argArray.count(); ++index) {
441         arguments[index] = ConstantFolder::GetConstantValueForVariable(*argArray[index]);
442     }
443 
444     auto Get = [&](int idx, int col) -> float {
445         return *arguments[idx]->getConstantValue(col);
446     };
447 
448     using namespace SkSL::dsl;
449     switch (intrinsic) {
450         // 8.1 : Angle and Trigonometry Functions
451         case k_radians_IntrinsicKind:
452             return evaluate_intrinsic<float>(context, arguments, returnType,
453                                              Intrinsics::evaluate_radians);
454         case k_degrees_IntrinsicKind:
455             return evaluate_intrinsic<float>(context, arguments, returnType,
456                                              Intrinsics::evaluate_degrees);
457         case k_sin_IntrinsicKind:
458             return evaluate_intrinsic<float>(context, arguments, returnType,
459                                              Intrinsics::evaluate_sin);
460         case k_cos_IntrinsicKind:
461             return evaluate_intrinsic<float>(context, arguments, returnType,
462                                              Intrinsics::evaluate_cos);
463         case k_tan_IntrinsicKind:
464             return evaluate_intrinsic<float>(context, arguments, returnType,
465                                              Intrinsics::evaluate_tan);
466         case k_sinh_IntrinsicKind:
467             return evaluate_intrinsic<float>(context, arguments, returnType,
468                                              Intrinsics::evaluate_sinh);
469         case k_cosh_IntrinsicKind:
470             return evaluate_intrinsic<float>(context, arguments, returnType,
471                                              Intrinsics::evaluate_cosh);
472         case k_tanh_IntrinsicKind:
473             return evaluate_intrinsic<float>(context, arguments, returnType,
474                                              Intrinsics::evaluate_tanh);
475         case k_asin_IntrinsicKind:
476             return evaluate_intrinsic<float>(context, arguments, returnType,
477                                              Intrinsics::evaluate_asin);
478         case k_acos_IntrinsicKind:
479             return evaluate_intrinsic<float>(context, arguments, returnType,
480                                              Intrinsics::evaluate_acos);
481         case k_atan_IntrinsicKind:
482             if (argArray.size() == 1) {
483                 return evaluate_intrinsic<float>(context, arguments, returnType,
484                                                  Intrinsics::evaluate_atan);
485             } else {
486                 return evaluate_pairwise_intrinsic(context, arguments, returnType,
487                                                    Intrinsics::evaluate_atan2);
488             }
489         case k_asinh_IntrinsicKind:
490             return evaluate_intrinsic<float>(context, arguments, returnType,
491                                              Intrinsics::evaluate_asinh);
492 
493         case k_acosh_IntrinsicKind:
494             return evaluate_intrinsic<float>(context, arguments, returnType,
495                                              Intrinsics::evaluate_acosh);
496         case k_atanh_IntrinsicKind:
497             return evaluate_intrinsic<float>(context, arguments, returnType,
498                                              Intrinsics::evaluate_atanh);
499         // 8.2 : Exponential Functions
500         case k_pow_IntrinsicKind:
501             return evaluate_pairwise_intrinsic(context, arguments, returnType,
502                                                Intrinsics::evaluate_pow);
503         case k_exp_IntrinsicKind:
504             return evaluate_intrinsic<float>(context, arguments, returnType,
505                                              Intrinsics::evaluate_exp);
506         case k_log_IntrinsicKind:
507             return evaluate_intrinsic<float>(context, arguments, returnType,
508                                              Intrinsics::evaluate_log);
509         case k_exp2_IntrinsicKind:
510             return evaluate_intrinsic<float>(context, arguments, returnType,
511                                              Intrinsics::evaluate_exp2);
512         case k_log2_IntrinsicKind:
513             return evaluate_intrinsic<float>(context, arguments, returnType,
514                                              Intrinsics::evaluate_log2);
515         case k_sqrt_IntrinsicKind:
516             return evaluate_intrinsic<float>(context, arguments, returnType,
517                                              Intrinsics::evaluate_sqrt);
518         case k_inversesqrt_IntrinsicKind:
519             return evaluate_intrinsic<float>(context, arguments, returnType,
520                                              Intrinsics::evaluate_inversesqrt);
521         // 8.3 : Common Functions
522         case k_abs_IntrinsicKind:
523             return evaluate_intrinsic_numeric(context, arguments, returnType,
524                                               Intrinsics::evaluate_abs);
525         case k_sign_IntrinsicKind:
526             return evaluate_intrinsic_numeric(context, arguments, returnType,
527                                               Intrinsics::evaluate_sign);
528         case k_floor_IntrinsicKind:
529             return evaluate_intrinsic<float>(context, arguments, returnType,
530                                              Intrinsics::evaluate_floor);
531         case k_ceil_IntrinsicKind:
532             return evaluate_intrinsic<float>(context, arguments, returnType,
533                                              Intrinsics::evaluate_ceil);
534         case k_fract_IntrinsicKind:
535             return evaluate_intrinsic<float>(context, arguments, returnType,
536                                              Intrinsics::evaluate_fract);
537         case k_mod_IntrinsicKind:
538             return evaluate_pairwise_intrinsic(context, arguments, returnType,
539                                                Intrinsics::evaluate_mod);
540         case k_min_IntrinsicKind:
541             return evaluate_pairwise_intrinsic(context, arguments, returnType,
542                                                Intrinsics::evaluate_min);
543         case k_max_IntrinsicKind:
544             return evaluate_pairwise_intrinsic(context, arguments, returnType,
545                                                Intrinsics::evaluate_max);
546         case k_clamp_IntrinsicKind:
547             return evaluate_3_way_intrinsic(context, arguments, returnType,
548                                             Intrinsics::evaluate_clamp);
549         case k_saturate_IntrinsicKind:
550             return evaluate_intrinsic<float>(context, arguments, returnType,
551                                              Intrinsics::evaluate_saturate);
552         case k_mix_IntrinsicKind:
553             if (arguments[2]->type().componentType().isBoolean()) {
554                 const SkSL::Type& numericType = arguments[0]->type().componentType();
555 
556                 if (numericType.isFloat()) {
557                     type_check_expression<float>(*arguments[0]);
558                     type_check_expression<float>(*arguments[1]);
559                 } else if (numericType.isInteger()) {
560                     type_check_expression<SKSL_INT>(*arguments[0]);
561                     type_check_expression<SKSL_INT>(*arguments[1]);
562                 } else if (numericType.isBoolean()) {
563                     type_check_expression<bool>(*arguments[0]);
564                     type_check_expression<bool>(*arguments[1]);
565                 } else {
566                     SkDEBUGFAILF("unsupported type %s", numericType.description().c_str());
567                     return nullptr;
568                 }
569                 return evaluate_n_way_intrinsic(context, arguments[0], arguments[1], arguments[2],
570                                                 returnType, Intrinsics::evaluate_mix);
571             } else {
572                 return evaluate_3_way_intrinsic(context, arguments, returnType,
573                                                 Intrinsics::evaluate_mix);
574             }
575         case k_step_IntrinsicKind:
576             return evaluate_pairwise_intrinsic(context, arguments, returnType,
577                                                Intrinsics::evaluate_step);
578         case k_smoothstep_IntrinsicKind:
579             return evaluate_3_way_intrinsic(context, arguments, returnType,
580                                             Intrinsics::evaluate_smoothstep);
581         case k_trunc_IntrinsicKind:
582             return evaluate_intrinsic<float>(context, arguments, returnType,
583                                              Intrinsics::evaluate_trunc);
584         case k_round_IntrinsicKind:      // GLSL `round` documents its rounding mode as unspecified
585         case k_roundEven_IntrinsicKind:  // and is allowed to behave identically to `roundEven`.
586             return evaluate_intrinsic<float>(context, arguments, returnType,
587                                              Intrinsics::evaluate_round);
588         case k_floatBitsToInt_IntrinsicKind:
589             return evaluate_intrinsic<float>(context, arguments, returnType,
590                                              Intrinsics::evaluate_floatBitsToInt);
591         case k_floatBitsToUint_IntrinsicKind:
592             return evaluate_intrinsic<float>(context, arguments, returnType,
593                                              Intrinsics::evaluate_floatBitsToUint);
594         case k_intBitsToFloat_IntrinsicKind:
595             return evaluate_intrinsic<SKSL_INT>(context, arguments, returnType,
596                                                 Intrinsics::evaluate_intBitsToFloat);
597         case k_uintBitsToFloat_IntrinsicKind:
598             return evaluate_intrinsic<SKSL_INT>(context, arguments, returnType,
599                                                 Intrinsics::evaluate_uintBitsToFloat);
600         // 8.4 : Floating-Point Pack and Unpack Functions
601         case k_packUnorm2x16_IntrinsicKind: {
602             auto Pack = [&](int n) -> unsigned int {
603                 float x = Get(0, n);
604                 return (int)std::round(Intrinsics::evaluate_clamp(x, 0.0, 1.0) * 65535.0);
605             };
606             return UInt(((Pack(0) << 0)  & 0x0000FFFF) |
607                         ((Pack(1) << 16) & 0xFFFF0000)).release();
608         }
609         case k_unpackUnorm2x16_IntrinsicKind: {
610             SKSL_INT x = *arguments[0]->getConstantValue(0);
611             return Float2(double((x >> 0)  & 0x0000FFFF) / 65535.0,
612                           double((x >> 16) & 0x0000FFFF) / 65535.0).release();
613         }
614         // 8.5 : Geometric Functions
615         case k_length_IntrinsicKind:
616             return coalesce_vector<float>(arguments, /*startingState=*/0, returnType,
617                                           Intrinsics::coalesce_length,
618                                           Intrinsics::finalize_length);
619         case k_distance_IntrinsicKind:
620             return coalesce_pairwise_vectors<float>(arguments, /*startingState=*/0, returnType,
621                                                     Intrinsics::coalesce_distance,
622                                                     Intrinsics::finalize_distance);
623         case k_dot_IntrinsicKind:
624             return coalesce_pairwise_vectors<float>(arguments, /*startingState=*/0, returnType,
625                                                     Intrinsics::coalesce_dot,
626                                                     /*finalize=*/nullptr);
627         case k_cross_IntrinsicKind: {
628             auto X = [&](int n) -> float { return Get(0, n); };
629             auto Y = [&](int n) -> float { return Get(1, n); };
630             SkASSERT(arguments[0]->type().columns() == 3);  // the vec2 form is not a real intrinsic
631 
632             double vec[3] = {X(1) * Y(2) - Y(1) * X(2),
633                              X(2) * Y(0) - Y(2) * X(0),
634                              X(0) * Y(1) - Y(0) * X(1)};
635             return assemble_compound(context, arguments[0]->fLine, returnType, vec);
636         }
637         case k_normalize_IntrinsicKind: {
638             auto Vec  = [&] { return DSLExpression{arguments[0]->clone()}; };
639             return (Vec() / Length(Vec())).release();
640         }
641         case k_faceforward_IntrinsicKind: {
642             auto N    = [&] { return DSLExpression{arguments[0]->clone()}; };
643             auto I    = [&] { return DSLExpression{arguments[1]->clone()}; };
644             auto NRef = [&] { return DSLExpression{arguments[2]->clone()}; };
645             return (N() * Select(Dot(NRef(), I()) < 0, 1, -1)).release();
646         }
647         case k_reflect_IntrinsicKind: {
648             auto I    = [&] { return DSLExpression{arguments[0]->clone()}; };
649             auto N    = [&] { return DSLExpression{arguments[1]->clone()}; };
650             return (I() - 2.0 * Dot(N(), I()) * N()).release();
651         }
652         case k_refract_IntrinsicKind: {
653             auto I    = [&] { return DSLExpression{arguments[0]->clone()}; };
654             auto N    = [&] { return DSLExpression{arguments[1]->clone()}; };
655             auto Eta  = [&] { return DSLExpression{arguments[2]->clone()}; };
656 
657             std::unique_ptr<Expression> k =
658                     (1 - Pow(Eta(), 2) * (1 - Pow(Dot(N(), I()), 2))).release();
659             if (!k->is<Literal>()) {
660                 return nullptr;
661             }
662             double kValue = k->as<Literal>().value();
663             return ((kValue < 0) ?
664                        (0 * I()) :
665                        (Eta() * I() - (Eta() * Dot(N(), I()) + std::sqrt(kValue)) * N())).release();
666         }
667 
668         // 8.6 : Matrix Functions
669         case k_matrixCompMult_IntrinsicKind:
670             return evaluate_pairwise_intrinsic(context, arguments, returnType,
671                                                Intrinsics::evaluate_matrixCompMult);
672         case k_transpose_IntrinsicKind: {
673             double mat[16];
674             int index = 0;
675             for (int c = 0; c < returnType.columns(); ++c) {
676                 for (int r = 0; r < returnType.rows(); ++r) {
677                     mat[index++] = Get(0, (returnType.columns() * r) + c);
678                 }
679             }
680             return assemble_compound(context, arguments[0]->fLine, returnType, mat);
681         }
682         case k_outerProduct_IntrinsicKind: {
683             double mat[16];
684             int index = 0;
685             for (int c = 0; c < returnType.columns(); ++c) {
686                 for (int r = 0; r < returnType.rows(); ++r) {
687                     mat[index++] = Get(0, r) * Get(1, c);
688                 }
689             }
690             return assemble_compound(context, arguments[0]->fLine, returnType, mat);
691         }
692         case k_determinant_IntrinsicKind: {
693             float mat[16];
694             extract_matrix(arguments[0], mat);
695             float determinant;
696             switch (arguments[0]->type().slotCount()) {
697                 case 4:
698                     determinant = SkInvert2x2Matrix(mat, /*outMatrix=*/nullptr);
699                     break;
700                 case 9:
701                     determinant = SkInvert3x3Matrix(mat, /*outMatrix=*/nullptr);
702                     break;
703                 case 16:
704                     determinant = SkInvert4x4Matrix(mat, /*outMatrix=*/nullptr);
705                     break;
706                 default:
707                     SkDEBUGFAILF("unsupported type %s", arguments[0]->type().description().c_str());
708                     return nullptr;
709             }
710             return Literal::MakeFloat(arguments[0]->fLine, determinant, &returnType);
711         }
712         case k_inverse_IntrinsicKind: {
713             float mat[16] = {};
714             extract_matrix(arguments[0], mat);
715             switch (arguments[0]->type().slotCount()) {
716                 case 4:
717                     if (SkInvert2x2Matrix(mat, mat) == 0.0f) {
718                         return nullptr;
719                     }
720                     break;
721                 case 9:
722                     if (SkInvert3x3Matrix(mat, mat) == 0.0f) {
723                         return nullptr;
724                     }
725                     break;
726                 case 16:
727                     if (SkInvert4x4Matrix(mat, mat) == 0.0f) {
728                         return nullptr;
729                     }
730                     break;
731                 default:
732                     SkDEBUGFAILF("unsupported type %s", arguments[0]->type().description().c_str());
733                     return nullptr;
734             }
735 
736             double dmat[16];
737             std::copy(mat, mat + SK_ARRAY_COUNT(mat), dmat);
738             return assemble_compound(context, arguments[0]->fLine, returnType, dmat);
739         }
740         // 8.7 : Vector Relational Functions
741         case k_lessThan_IntrinsicKind:
742             return optimize_comparison(context, arguments, Intrinsics::compare_lessThan);
743 
744         case k_lessThanEqual_IntrinsicKind:
745             return optimize_comparison(context, arguments, Intrinsics::compare_lessThanEqual);
746 
747         case k_greaterThan_IntrinsicKind:
748             return optimize_comparison(context, arguments, Intrinsics::compare_greaterThan);
749 
750         case k_greaterThanEqual_IntrinsicKind:
751             return optimize_comparison(context, arguments, Intrinsics::compare_greaterThanEqual);
752 
753         case k_equal_IntrinsicKind:
754             return optimize_comparison(context, arguments, Intrinsics::compare_equal);
755 
756         case k_notEqual_IntrinsicKind:
757             return optimize_comparison(context, arguments, Intrinsics::compare_notEqual);
758 
759         case k_any_IntrinsicKind:
760             return coalesce_vector<bool>(arguments, /*startingState=*/false, returnType,
761                                          Intrinsics::coalesce_any,
762                                          /*finalize=*/nullptr);
763         case k_all_IntrinsicKind:
764             return coalesce_vector<bool>(arguments, /*startingState=*/true, returnType,
765                                          Intrinsics::coalesce_all,
766                                          /*finalize=*/nullptr);
767         case k_not_IntrinsicKind:
768             return evaluate_intrinsic<bool>(context, arguments, returnType,
769                                             Intrinsics::evaluate_not);
770         default:
771             return nullptr;
772     }
773 }
774 
hasProperty(Property property) const775 bool FunctionCall::hasProperty(Property property) const {
776     if (property == Property::kSideEffects &&
777         (this->function().modifiers().fFlags & Modifiers::kHasSideEffects_Flag)) {
778         return true;
779     }
780     for (const auto& arg : this->arguments()) {
781         if (arg->hasProperty(property)) {
782             return true;
783         }
784     }
785     return false;
786 }
787 
clone() const788 std::unique_ptr<Expression> FunctionCall::clone() const {
789     ExpressionArray cloned;
790     cloned.reserve_back(this->arguments().size());
791     for (const std::unique_ptr<Expression>& arg : this->arguments()) {
792         cloned.push_back(arg->clone());
793     }
794     return std::make_unique<FunctionCall>(
795             fLine, &this->type(), &this->function(), std::move(cloned));
796 }
797 
description() const798 String FunctionCall::description() const {
799     String result = String(this->function().name()) + "(";
800     String separator;
801     for (const std::unique_ptr<Expression>& arg : this->arguments()) {
802         result += separator;
803         result += arg->description();
804         separator = ", ";
805     }
806     result += ")";
807     return result;
808 }
809 
810 /**
811  * Determines the cost of coercing the arguments of a function to the required types. Cost has no
812  * particular meaning other than "lower costs are preferred". Returns CoercionCost::Impossible() if
813  * the call is not valid.
814  */
CallCost(const Context & context,const FunctionDeclaration & function,const ExpressionArray & arguments)815 CoercionCost FunctionCall::CallCost(const Context& context, const FunctionDeclaration& function,
816         const ExpressionArray& arguments){
817     if (context.fConfig->strictES2Mode() &&
818         (function.modifiers().fFlags & Modifiers::kES3_Flag)) {
819         return CoercionCost::Impossible();
820     }
821     if (function.parameters().size() != arguments.size()) {
822         return CoercionCost::Impossible();
823     }
824     FunctionDeclaration::ParamTypes types;
825     const Type* ignored;
826     if (!function.determineFinalTypes(arguments, &types, &ignored)) {
827         return CoercionCost::Impossible();
828     }
829     CoercionCost total = CoercionCost::Free();
830     for (size_t i = 0; i < arguments.size(); i++) {
831         total = total + arguments[i]->coercionCost(*types[i]);
832     }
833     return total;
834 }
835 
FindBestFunctionForCall(const Context & context,const std::vector<const FunctionDeclaration * > & functions,const ExpressionArray & arguments)836 const FunctionDeclaration* FunctionCall::FindBestFunctionForCall(
837         const Context& context,
838         const std::vector<const FunctionDeclaration*>& functions,
839         const ExpressionArray& arguments) {
840     if (functions.size() == 1) {
841         return functions.front();
842     }
843     CoercionCost bestCost = CoercionCost::Impossible();
844     const FunctionDeclaration* best = nullptr;
845     for (const auto& f : functions) {
846         CoercionCost cost = CallCost(context, *f, arguments);
847         if (cost < bestCost) {
848             bestCost = cost;
849             best = f;
850         }
851     }
852     return best;
853 }
854 
Convert(const Context & context,int line,std::unique_ptr<Expression> functionValue,ExpressionArray arguments)855 std::unique_ptr<Expression> FunctionCall::Convert(const Context& context,
856                                                   int line,
857                                                   std::unique_ptr<Expression> functionValue,
858                                                   ExpressionArray arguments) {
859     switch (functionValue->kind()) {
860         case Expression::Kind::kTypeReference:
861             return Constructor::Convert(context,
862                                         line,
863                                         functionValue->as<TypeReference>().value(),
864                                         std::move(arguments));
865         case Expression::Kind::kExternalFunctionReference: {
866             const ExternalFunction& f = functionValue->as<ExternalFunctionReference>().function();
867             int count = f.callParameterCount();
868             if (count != (int) arguments.size()) {
869                 context.fErrors->error(line,
870                         "external function expected " + to_string(count) +
871                         " arguments, but found " + to_string((int)arguments.size()));
872                 return nullptr;
873             }
874             static constexpr int PARAMETER_MAX = 16;
875             SkASSERT(count < PARAMETER_MAX);
876             const Type* types[PARAMETER_MAX];
877             f.getCallParameterTypes(types);
878             for (int i = 0; i < count; ++i) {
879                 arguments[i] = types[i]->coerceExpression(std::move(arguments[i]), context);
880                 if (!arguments[i]) {
881                     return nullptr;
882                 }
883             }
884             return std::make_unique<ExternalFunctionCall>(line, &f, std::move(arguments));
885         }
886         case Expression::Kind::kFunctionReference: {
887             const FunctionReference& ref = functionValue->as<FunctionReference>();
888             const std::vector<const FunctionDeclaration*>& functions = ref.functions();
889             const FunctionDeclaration* best = FindBestFunctionForCall(context, functions,
890                     arguments);
891             if (best) {
892                 return FunctionCall::Convert(context, line, *best, std::move(arguments));
893             }
894             String msg = "no match for " + functions[0]->name() + "(";
895             String separator;
896             for (size_t i = 0; i < arguments.size(); i++) {
897                 msg += separator;
898                 separator = ", ";
899                 msg += arguments[i]->type().displayName();
900             }
901             msg += ")";
902             context.fErrors->error(line, msg);
903             return nullptr;
904         }
905         case Expression::Kind::kMethodReference: {
906             MethodReference& ref = functionValue->as<MethodReference>();
907             arguments.push_back(std::move(ref.self()));
908 
909             const std::vector<const FunctionDeclaration*>& functions = ref.functions();
910             const FunctionDeclaration* best = FindBestFunctionForCall(context, functions,
911                     arguments);
912             if (best) {
913                 return FunctionCall::Convert(context, line, *best, std::move(arguments));
914             }
915             String msg = "no match for " + arguments.back()->type().displayName() +
916                          "::" + functions[0]->name().substr(1) + "(";
917             String separator;
918             for (size_t i = 0; i < arguments.size() - 1; i++) {
919                 msg += separator;
920                 separator = ", ";
921                 msg += arguments[i]->type().displayName();
922             }
923             msg += ")";
924             context.fErrors->error(line, msg);
925             return nullptr;
926         }
927         case Expression::Kind::kPoison:
928             return functionValue;
929         default:
930             context.fErrors->error(line, "not a function");
931             return nullptr;
932     }
933 }
934 
Convert(const Context & context,int line,const FunctionDeclaration & function,ExpressionArray arguments)935 std::unique_ptr<Expression> FunctionCall::Convert(const Context& context,
936                                                   int line,
937                                                   const FunctionDeclaration& function,
938                                                   ExpressionArray arguments) {
939     // Reject ES3 function calls in strict ES2 mode.
940     if (context.fConfig->strictES2Mode() && (function.modifiers().fFlags & Modifiers::kES3_Flag)) {
941         context.fErrors->error(line, "call to '" + function.description() + "' is not supported");
942         return nullptr;
943     }
944 
945     // Reject function calls with the wrong number of arguments.
946     if (function.parameters().size() != arguments.size()) {
947         String msg = "call to '" + function.name() + "' expected " +
948                      to_string((int)function.parameters().size()) + " argument";
949         if (function.parameters().size() != 1) {
950             msg += "s";
951         }
952         msg += ", but found " + to_string(arguments.count());
953         context.fErrors->error(line, msg);
954         return nullptr;
955     }
956 
957     // Resolve generic types.
958     FunctionDeclaration::ParamTypes types;
959     const Type* returnType;
960     if (!function.determineFinalTypes(arguments, &types, &returnType)) {
961         String msg = "no match for " + function.name() + "(";
962         String separator;
963         for (const std::unique_ptr<Expression>& arg : arguments) {
964             msg += separator;
965             msg += arg->type().displayName();
966             separator = ", ";
967         }
968         msg += ")";
969         context.fErrors->error(line, msg);
970         return nullptr;
971     }
972 
973     for (size_t i = 0; i < arguments.size(); i++) {
974         // Coerce each argument to the proper type.
975         arguments[i] = types[i]->coerceExpression(std::move(arguments[i]), context);
976         if (!arguments[i]) {
977             return nullptr;
978         }
979         // Update the refKind on out-parameters, and ensure that they are actually assignable.
980         const Modifiers& paramModifiers = function.parameters()[i]->modifiers();
981         if (paramModifiers.fFlags & Modifiers::kOut_Flag) {
982             const VariableRefKind refKind = paramModifiers.fFlags & Modifiers::kIn_Flag
983                                                     ? VariableReference::RefKind::kReadWrite
984                                                     : VariableReference::RefKind::kPointer;
985             if (!Analysis::UpdateVariableRefKind(arguments[i].get(), refKind, context.fErrors)) {
986                 return nullptr;
987             }
988         }
989     }
990 
991     if (function.intrinsicKind() == k_eval_IntrinsicKind) {
992         // This is a method call on an effect child. Translate it into a ChildCall, which simplifies
993         // handling in the generators and analysis code.
994         const Variable& child = *arguments.back()->as<VariableReference>().variable();
995         arguments.pop_back();
996         return ChildCall::Make(context, line, returnType, child, std::move(arguments));
997     }
998 
999     return Make(context, line, returnType, function, std::move(arguments));
1000 }
1001 
Make(const Context & context,int line,const Type * returnType,const FunctionDeclaration & function,ExpressionArray arguments)1002 std::unique_ptr<Expression> FunctionCall::Make(const Context& context,
1003                                                int line,
1004                                                const Type* returnType,
1005                                                const FunctionDeclaration& function,
1006                                                ExpressionArray arguments) {
1007     SkASSERT(function.parameters().size() == arguments.size());
1008 
1009     // We might be able to optimize built-in intrinsics.
1010     if (function.isIntrinsic() && has_compile_time_constant_arguments(arguments)) {
1011         // The function is an intrinsic and all inputs are compile-time constants. Optimize it.
1012         if (std::unique_ptr<Expression> expr = optimize_intrinsic_call(context,
1013                                                                        function.intrinsicKind(),
1014                                                                        arguments,
1015                                                                        *returnType)) {
1016             return expr;
1017         }
1018     }
1019 
1020     return std::make_unique<FunctionCall>(line, returnType, &function, std::move(arguments));
1021 }
1022 
1023 }  // namespace SkSL
1024