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