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