Update rive-cpp to 2.0 version
[platform/core/uifw/rive-tizen.git] / submodule / skia / src / sksl / ir / SkSLFunctionDeclaration.cpp
1 /*
2  * Copyright 2021 Google LLC.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7
8 #include "src/sksl/ir/SkSLFunctionDeclaration.h"
9
10 #include "include/private/SkStringView.h"
11 #include "src/sksl/SkSLCompiler.h"
12 #include "src/sksl/ir/SkSLUnresolvedFunction.h"
13
14 namespace SkSL {
15
16 static IntrinsicKind identify_intrinsic(std::string_view functionName) {
17     #define SKSL_INTRINSIC(name) {#name, k_##name##_IntrinsicKind},
18     static const auto* kAllIntrinsics = new SkTHashMap<std::string_view, IntrinsicKind>{
19         SKSL_INTRINSIC_LIST
20     };
21     #undef SKSL_INTRINSIC
22
23     if (skstd::starts_with(functionName, '$')) {
24         functionName.remove_prefix(1);
25     }
26
27     IntrinsicKind* kind = kAllIntrinsics->find(functionName);
28     return kind ? *kind : kNotIntrinsic;
29 }
30
31 static bool check_modifiers(const Context& context,
32                             Position pos,
33                             const Modifiers& modifiers) {
34     const int permitted = Modifiers::kHasSideEffects_Flag |
35                           Modifiers::kInline_Flag |
36                           Modifiers::kNoInline_Flag |
37                           (context.fConfig->fIsBuiltinCode ? Modifiers::kES3_Flag : 0);
38     modifiers.checkPermitted(context, pos, permitted, /*permittedLayoutFlags=*/0);
39     if ((modifiers.fFlags & Modifiers::kInline_Flag) &&
40         (modifiers.fFlags & Modifiers::kNoInline_Flag)) {
41         context.fErrors->error(pos, "functions cannot be both 'inline' and 'noinline'");
42         return false;
43     }
44     return true;
45 }
46
47 static bool check_return_type(const Context& context, Position pos, const Type& returnType) {
48     ErrorReporter& errors = *context.fErrors;
49     if (returnType.isArray()) {
50         errors.error(pos, "functions may not return type '" + returnType.displayName() + "'");
51         return false;
52     }
53     if (context.fConfig->strictES2Mode() && returnType.isOrContainsArray()) {
54         errors.error(pos, "functions may not return structs containing arrays");
55         return false;
56     }
57     if (!context.fConfig->fIsBuiltinCode && returnType.componentType().isOpaque()) {
58         errors.error(pos, "functions may not return opaque type '" + returnType.displayName() +
59                 "'");
60         return false;
61     }
62     return true;
63 }
64
65 static bool check_parameters(const Context& context,
66                              std::vector<std::unique_ptr<Variable>>& parameters,
67                              bool isMain) {
68     auto typeIsValidForColor = [&](const Type& type) {
69         return type.matches(*context.fTypes.fHalf4) || type.matches(*context.fTypes.fFloat4);
70     };
71
72     // The first color parameter passed to main() is the input color; the second is the dest color.
73     static constexpr int kBuiltinColorIDs[] = {SK_INPUT_COLOR_BUILTIN, SK_DEST_COLOR_BUILTIN};
74     unsigned int builtinColorIndex = 0;
75
76     // Check modifiers on each function parameter.
77     for (auto& param : parameters) {
78         param->modifiers().checkPermitted(context, param->modifiersPosition(),
79                 Modifiers::kConst_Flag | Modifiers::kIn_Flag | Modifiers::kOut_Flag,
80                 /*permittedLayoutFlags=*/0);
81         const Type& type = param->type();
82         // Only the (builtin) declarations of 'sample' are allowed to have shader/colorFilter or FP
83         // parameters. You can pass other opaque types to functions safely; this restriction is
84         // specific to "child" objects.
85         if (type.isEffectChild() && !context.fConfig->fIsBuiltinCode) {
86             context.fErrors->error(param->fPosition, "parameters of type '" + type.displayName() +
87                     "' not allowed");
88             return false;
89         }
90
91         Modifiers m = param->modifiers();
92         bool modifiersChanged = false;
93
94         // The `in` modifier on function parameters is implicit, so we can replace `in float x` with
95         // `float x`. This prevents any ambiguity when matching a function by its param types.
96         if (Modifiers::kIn_Flag == (m.fFlags & (Modifiers::kOut_Flag | Modifiers::kIn_Flag))) {
97             m.fFlags &= ~(Modifiers::kOut_Flag | Modifiers::kIn_Flag);
98             modifiersChanged = true;
99         }
100
101         if (isMain) {
102             if (ProgramConfig::IsRuntimeEffect(context.fConfig->fKind) &&
103                 context.fConfig->fKind != ProgramKind::kMeshFragment &&
104                 context.fConfig->fKind != ProgramKind::kMeshVertex) {
105                 // We verify that the signature is fully correct later. For now, if this is a
106                 // runtime effect of any flavor, a float2 param is supposed to be the coords, and a
107                 // half4/float parameter is supposed to be the input or destination color:
108                 if (type.matches(*context.fTypes.fFloat2)) {
109                     m.fLayout.fBuiltin = SK_MAIN_COORDS_BUILTIN;
110                     modifiersChanged = true;
111                 } else if (typeIsValidForColor(type) &&
112                            builtinColorIndex < SK_ARRAY_COUNT(kBuiltinColorIDs)) {
113                     m.fLayout.fBuiltin = kBuiltinColorIDs[builtinColorIndex++];
114                     modifiersChanged = true;
115                 }
116             } else if (ProgramConfig::IsFragment(context.fConfig->fKind)) {
117                 // For testing purposes, we have .sksl inputs that are treated as both runtime
118                 // effects and fragment shaders. To make that work, fragment shaders are allowed to
119                 // have a coords parameter.
120                 if (type.matches(*context.fTypes.fFloat2)) {
121                     m.fLayout.fBuiltin = SK_MAIN_COORDS_BUILTIN;
122                     modifiersChanged = true;
123                 }
124             }
125         }
126
127         if (modifiersChanged) {
128             param->setModifiers(context.fModifiersPool->add(m));
129         }
130     }
131     return true;
132 }
133
134 static bool check_main_signature(const Context& context, Position pos, const Type& returnType,
135                                  std::vector<std::unique_ptr<Variable>>& parameters) {
136     ErrorReporter& errors = *context.fErrors;
137     ProgramKind kind = context.fConfig->fKind;
138
139     auto typeIsValidForColor = [&](const Type& type) {
140         return type.matches(*context.fTypes.fHalf4) || type.matches(*context.fTypes.fFloat4);
141     };
142
143     auto typeIsValidForAttributes = [&](const Type& type) {
144         return type.isStruct() && type.name() == "Attributes";
145     };
146
147     auto typeIsValidForVaryings = [&](const Type& type) {
148         return type.isStruct() && type.name() == "Varyings";
149     };
150
151     auto paramIsCoords = [&](int idx) {
152         const Variable& p = *parameters[idx];
153         return p.type().matches(*context.fTypes.fFloat2) &&
154                p.modifiers().fFlags == 0 &&
155                p.modifiers().fLayout.fBuiltin == SK_MAIN_COORDS_BUILTIN;
156     };
157
158     auto paramIsBuiltinColor = [&](int idx, int builtinID) {
159         const Variable& p = *parameters[idx];
160         return typeIsValidForColor(p.type()) &&
161                p.modifiers().fFlags == 0 &&
162                p.modifiers().fLayout.fBuiltin == builtinID;
163     };
164
165     auto paramIsInAttributes = [&](int idx) {
166         const Variable& p = *parameters[idx];
167         return typeIsValidForAttributes(p.type()) && p.modifiers().fFlags == 0;
168     };
169
170     auto paramIsOutVaryings = [&](int idx) {
171         const Variable& p = *parameters[idx];
172         return typeIsValidForVaryings(p.type()) && p.modifiers().fFlags == Modifiers::kOut_Flag;
173     };
174
175     auto paramIsInVaryings = [&](int idx) {
176         const Variable& p = *parameters[idx];
177         return typeIsValidForVaryings(p.type()) && p.modifiers().fFlags == 0;
178     };
179
180     auto paramIsOutColor = [&](int idx) {
181         const Variable& p = *parameters[idx];
182         return typeIsValidForColor(p.type()) && p.modifiers().fFlags == Modifiers::kOut_Flag;
183     };
184
185     auto paramIsInputColor = [&](int n) { return paramIsBuiltinColor(n, SK_INPUT_COLOR_BUILTIN); };
186     auto paramIsDestColor  = [&](int n) { return paramIsBuiltinColor(n, SK_DEST_COLOR_BUILTIN); };
187
188     switch (kind) {
189         case ProgramKind::kRuntimeColorFilter: {
190             // (half4|float4) main(half4|float4)
191             if (!typeIsValidForColor(returnType)) {
192                 errors.error(pos, "'main' must return: 'vec4', 'float4', or 'half4'");
193                 return false;
194             }
195             bool validParams = (parameters.size() == 1 && paramIsInputColor(0));
196             if (!validParams) {
197                 errors.error(pos, "'main' parameter must be 'vec4', 'float4', or 'half4'");
198                 return false;
199             }
200             break;
201         }
202         case ProgramKind::kRuntimeShader:
203         case ProgramKind::kPrivateRuntimeShader: {
204             // (half4|float4) main(float2)  -or-  (half4|float4) main(float2, half4|float4)
205             if (!typeIsValidForColor(returnType)) {
206                 errors.error(pos, "'main' must return: 'vec4', 'float4', or 'half4'");
207                 return false;
208             }
209             bool validParams =
210                     (parameters.size() == 1 && paramIsCoords(0)) ||
211                     (parameters.size() == 2 && paramIsCoords(0) && paramIsInputColor(1));
212             if (!validParams) {
213                 errors.error(pos, "'main' parameters must be (float2, (vec4|float4|half4)?)");
214                 return false;
215             }
216             break;
217         }
218         case ProgramKind::kRuntimeBlender: {
219             // (half4|float4) main(half4|float4, half4|float4)
220             if (!typeIsValidForColor(returnType)) {
221                 errors.error(pos, "'main' must return: 'vec4', 'float4', or 'half4'");
222                 return false;
223             }
224             if (!(parameters.size() == 2 &&
225                   paramIsInputColor(0) &&
226                   paramIsDestColor(1))) {
227                 errors.error(pos, "'main' parameters must be (vec4|float4|half4, "
228                         "vec4|float4|half4)");
229                 return false;
230             }
231             break;
232         }
233         case ProgramKind::kMeshVertex: {
234             // float2 main(Attributes, out Varyings)
235             if (!returnType.matches(*context.fTypes.fFloat2)) {
236                 errors.error(pos, "'main' must return: 'vec2' or 'float2'");
237                 return false;
238             }
239             if (!(parameters.size() == 2 && paramIsInAttributes(0) && paramIsOutVaryings(1))) {
240                 errors.error(pos, "'main' parameters must be (Attributes, out Varyings");
241                 return false;
242             }
243             break;
244         }
245         case ProgramKind::kMeshFragment: {
246             // float2 main(Varyings) -or- float2 main(Varyings, out half4|float4]) -or-
247             // void main(Varyings) -or- void main(Varyings, out half4|float4])
248             if (!returnType.matches(*context.fTypes.fFloat2) &&
249                 !returnType.matches(*context.fTypes.fVoid)) {
250                 errors.error(pos, "'main' must return: 'vec2', 'float2', 'or' 'void'");
251                 return false;
252             }
253             if (!((parameters.size() == 1 && paramIsInVaryings(0)) ||
254                   (parameters.size() == 2 && paramIsInVaryings(0) && paramIsOutColor(1)))) {
255                 errors.error(pos, "'main' parameters must be (Varyings, (out (half4|float4))?)");
256                 return false;
257             }
258             break;
259         }
260         case ProgramKind::kGeneric:
261             // No rules apply here
262             break;
263         case ProgramKind::kFragment:
264         case ProgramKind::kGraphiteFragment: {
265             bool validParams = (parameters.size() == 0) ||
266                                (parameters.size() == 1 && paramIsCoords(0));
267             if (!validParams) {
268                 errors.error(pos, "shader 'main' must be main() or main(float2)");
269                 return false;
270             }
271             break;
272         }
273         case ProgramKind::kVertex:
274         case ProgramKind::kGraphiteVertex:
275             if (parameters.size()) {
276                 errors.error(pos, "shader 'main' must have zero parameters");
277                 return false;
278             }
279             break;
280     }
281     return true;
282 }
283
284 /**
285  * Checks for a previously existing declaration of this function, reporting errors if there is an
286  * incompatible symbol. Returns true and sets outExistingDecl to point to the existing declaration
287  * (or null if none) on success, returns false on error.
288  */
289 static bool find_existing_declaration(const Context& context,
290                                       SymbolTable& symbols,
291                                       Position pos,
292                                       std::string_view name,
293                                       std::vector<std::unique_ptr<Variable>>& parameters,
294                                       Position returnTypePos,
295                                       const Type* returnType,
296                                       const FunctionDeclaration** outExistingDecl) {
297     ErrorReporter& errors = *context.fErrors;
298     const Symbol* entry = symbols[name];
299     *outExistingDecl = nullptr;
300     if (entry) {
301         std::vector<const FunctionDeclaration*> functions;
302         switch (entry->kind()) {
303             case Symbol::Kind::kUnresolvedFunction:
304                 functions = entry->as<UnresolvedFunction>().functions();
305                 break;
306             case Symbol::Kind::kFunctionDeclaration:
307                 functions.push_back(&entry->as<FunctionDeclaration>());
308                 break;
309             default:
310                 errors.error(pos, "symbol '" + std::string(name) + "' was already defined");
311                 return false;
312         }
313         for (const FunctionDeclaration* other : functions) {
314             SkASSERT(name == other->name());
315             if (parameters.size() != other->parameters().size()) {
316                 continue;
317             }
318             bool match = true;
319             for (size_t i = 0; i < parameters.size(); i++) {
320                 if (!parameters[i]->type().matches(other->parameters()[i]->type())) {
321                     match = false;
322                     break;
323                 }
324             }
325             if (!match) {
326                 continue;
327             }
328             if (!returnType->matches(other->returnType())) {
329                 std::vector<const Variable*> paramPtrs;
330                 paramPtrs.reserve(parameters.size());
331                 for (std::unique_ptr<Variable>& param : parameters) {
332                     paramPtrs.push_back(param.get());
333                 }
334                 FunctionDeclaration invalidDecl(pos,
335                                                 &other->modifiers(),
336                                                 name,
337                                                 std::move(paramPtrs),
338                                                 returnType,
339                                                 context.fConfig->fIsBuiltinCode);
340                 errors.error(returnTypePos,
341                              "functions '" + invalidDecl.description() + "' and '" +
342                              other->description() + "' differ only in return type");
343                 return false;
344             }
345             for (size_t i = 0; i < parameters.size(); i++) {
346                 if (parameters[i]->modifiers() != other->parameters()[i]->modifiers()) {
347                     errors.error(parameters[i]->fPosition, "modifiers on parameter " +
348                             std::to_string(i + 1) + " differ between declaration and definition");
349                     return false;
350                 }
351             }
352             if (other->definition() && !other->isBuiltin()) {
353                 errors.error(pos, "duplicate definition of " + other->description());
354                 return false;
355             }
356             *outExistingDecl = other;
357             break;
358         }
359     }
360     return true;
361 }
362
363 FunctionDeclaration::FunctionDeclaration(Position pos,
364                                          const Modifiers* modifiers,
365                                          std::string_view name,
366                                          std::vector<const Variable*> parameters,
367                                          const Type* returnType,
368                                          bool builtin)
369         : INHERITED(pos, kSymbolKind, name, /*type=*/nullptr)
370         , fDefinition(nullptr)
371         , fModifiers(modifiers)
372         , fParameters(std::move(parameters))
373         , fReturnType(returnType)
374         , fBuiltin(builtin)
375         , fIsMain(name == "main")
376         , fIntrinsicKind(builtin ? identify_intrinsic(name) : kNotIntrinsic) {}
377
378 const FunctionDeclaration* FunctionDeclaration::Convert(
379         const Context& context,
380         SymbolTable& symbols,
381         Position pos,
382         Position modifiersPosition,
383         const Modifiers* modifiers,
384         std::string_view name,
385         std::vector<std::unique_ptr<Variable>> parameters,
386         Position returnTypePos,
387         const Type* returnType) {
388     bool isMain = (name == "main");
389
390     const FunctionDeclaration* decl = nullptr;
391     if (!check_modifiers(context, modifiersPosition, *modifiers) ||
392         !check_return_type(context, returnTypePos, *returnType) ||
393         !check_parameters(context, parameters, isMain) ||
394         (isMain && !check_main_signature(context, pos, *returnType, parameters)) ||
395         !find_existing_declaration(context, symbols, pos, name, parameters, returnTypePos,
396                                    returnType, &decl)) {
397         return nullptr;
398     }
399     std::vector<const Variable*> finalParameters;
400     finalParameters.reserve(parameters.size());
401     for (std::unique_ptr<Variable>& param : parameters) {
402         finalParameters.push_back(symbols.takeOwnershipOfSymbol(std::move(param)));
403     }
404     if (decl) {
405         return decl;
406     }
407     auto result = std::make_unique<FunctionDeclaration>(pos,
408                                                         modifiers,
409                                                         name,
410                                                         std::move(finalParameters),
411                                                         returnType,
412                                                         context.fConfig->fIsBuiltinCode);
413     return symbols.add(std::move(result));
414 }
415
416 std::string FunctionDeclaration::mangledName() const {
417     if ((this->isBuiltin() && !this->definition()) || this->isMain()) {
418         // Builtins without a definition (like `sin` or `sqrt`) must use their real names.
419         return std::string(this->name());
420     }
421     // Built-in functions can have a $ prefix, which will fail to compile in GLSL/Metal. Remove the
422     // $ and add a unique mangling specifier, so user code can't conflict with the name.
423     std::string_view name = this->name();
424     const char* builtinMarker = "";
425     if (skstd::starts_with(name, '$')) {
426         name.remove_prefix(1);
427         builtinMarker = "Q";  // a unique, otherwise-unused mangle character
428     }
429     // GLSL forbids two underscores in a row; add an extra character if necessary to avoid this.
430     const char* splitter = skstd::ends_with(name, '_') ? "x_" : "_";
431     // Rename function to `funcname_returntypeparamtypes`.
432     std::string result = std::string(name) + splitter + builtinMarker +
433                          this->returnType().abbreviatedName();
434     for (const Variable* p : this->parameters()) {
435         result += p->type().abbreviatedName();
436     }
437     return result;
438 }
439
440 std::string FunctionDeclaration::description() const {
441     std::string result = this->returnType().displayName() + " " + std::string(this->name()) + "(";
442     std::string separator;
443     for (const Variable* p : this->parameters()) {
444         result += separator;
445         separator = ", ";
446         result += p->type().displayName();
447         result += " ";
448         result += p->name();
449     }
450     result += ")";
451     return result;
452 }
453
454 bool FunctionDeclaration::matches(const FunctionDeclaration& f) const {
455     if (this->name() != f.name()) {
456         return false;
457     }
458     const std::vector<const Variable*>& parameters = this->parameters();
459     const std::vector<const Variable*>& otherParameters = f.parameters();
460     if (parameters.size() != otherParameters.size()) {
461         return false;
462     }
463     for (size_t i = 0; i < parameters.size(); i++) {
464         if (!parameters[i]->type().matches(otherParameters[i]->type())) {
465             return false;
466         }
467     }
468     return true;
469 }
470
471 bool FunctionDeclaration::determineFinalTypes(const ExpressionArray& arguments,
472                                               ParamTypes* outParameterTypes,
473                                               const Type** outReturnType) const {
474     const std::vector<const Variable*>& parameters = this->parameters();
475     SkASSERT(arguments.size() == parameters.size());
476
477     outParameterTypes->reserve_back(arguments.size());
478     int genericIndex = -1;
479     for (size_t i = 0; i < arguments.size(); i++) {
480         // Non-generic parameters are final as-is.
481         const Type& parameterType = parameters[i]->type();
482         if (parameterType.typeKind() != Type::TypeKind::kGeneric) {
483             outParameterTypes->push_back(&parameterType);
484             continue;
485         }
486         // We use the first generic parameter we find to lock in the generic index;
487         // e.g. if we find `float3` here, all `$genType`s will be assumed to be `float3`.
488         const std::vector<const Type*>& types = parameterType.coercibleTypes();
489         if (genericIndex == -1) {
490             for (size_t j = 0; j < types.size(); j++) {
491                 if (arguments[i]->type().canCoerceTo(*types[j], /*allowNarrowing=*/true)) {
492                     genericIndex = j;
493                     break;
494                 }
495             }
496             if (genericIndex == -1) {
497                 // The passed-in type wasn't a match for ANY of the generic possibilities.
498                 // This function isn't a match at all.
499                 return false;
500             }
501         }
502         outParameterTypes->push_back(types[genericIndex]);
503     }
504     // Apply the generic index to our return type.
505     const Type& returnType = this->returnType();
506     if (returnType.typeKind() == Type::TypeKind::kGeneric) {
507         if (genericIndex == -1) {
508             // We don't support functions with a generic return type and no other generics.
509             return false;
510         }
511         *outReturnType = returnType.coercibleTypes()[genericIndex];
512     } else {
513         *outReturnType = &returnType;
514     }
515     return true;
516 }
517
518 }  // namespace SkSL