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