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