blob: 8dc29a290147e1a4cf8ae0882e98973b8c8911fe [file] [log] [blame]
Ethan Nicholas371f6e12021-05-04 14:30:02 -04001/*
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 "src/sksl/SkSLCompiler.h"
11#include "src/sksl/SkSLIRGenerator.h"
12#include "src/sksl/ir/SkSLUnresolvedFunction.h"
13
14namespace SkSL {
15
John Stilesffc01892021-08-19 10:32:01 -040016static IntrinsicKind identify_intrinsic(skstd::string_view functionName) {
John Stilesf96cb712021-05-05 22:17:04 -040017 #define SKSL_INTRINSIC(name) {#name, k_##name##_IntrinsicKind},
John Stilesffc01892021-08-19 10:32:01 -040018 static const auto* kAllIntrinsics = new std::unordered_map<skstd::string_view, IntrinsicKind>{
John Stilesf96cb712021-05-05 22:17:04 -040019 SKSL_INTRINSIC_LIST
20 };
21 #undef SKSL_INTRINSIC
22
Brian Osman3099f792021-09-01 13:12:16 -040023 if (functionName.starts_with('$')) {
24 functionName.remove_prefix(1);
25 }
26
John Stilesf96cb712021-05-05 22:17:04 -040027 auto iter = kAllIntrinsics->find(functionName);
28 if (iter != kAllIntrinsics->end()) {
29 return iter->second;
30 }
31
32 return kNotIntrinsic;
33}
34
John Stilesefde90d2021-08-12 23:06:24 -040035static bool check_modifiers(const Context& context,
Ethan Nicholas89cfde12021-09-27 11:20:34 -040036 int line,
John Stilesefde90d2021-08-12 23:06:24 -040037 const Modifiers& modifiers,
38 bool isBuiltin) {
39 const int permitted = Modifiers::kHasSideEffects_Flag |
40 Modifiers::kInline_Flag |
41 Modifiers::kNoInline_Flag |
42 (isBuiltin ? Modifiers::kES3_Flag : 0);
Ethan Nicholas89cfde12021-09-27 11:20:34 -040043 IRGenerator::CheckModifiers(context, line, modifiers, permitted, /*permittedLayoutFlags=*/0);
Ethan Nicholas371f6e12021-05-04 14:30:02 -040044 if ((modifiers.fFlags & Modifiers::kInline_Flag) &&
45 (modifiers.fFlags & Modifiers::kNoInline_Flag)) {
Ethan Nicholas89cfde12021-09-27 11:20:34 -040046 context.fErrors->error(line, "functions cannot be both 'inline' and 'noinline'");
Ethan Nicholas371f6e12021-05-04 14:30:02 -040047 return false;
48 }
49 return true;
50}
51
Ethan Nicholas89cfde12021-09-27 11:20:34 -040052static bool check_return_type(const Context& context, int line, const Type& returnType,
Ethan Nicholas371f6e12021-05-04 14:30:02 -040053 bool isBuiltin) {
Ethan Nicholas39f6da42021-08-23 13:10:07 -040054 ErrorReporter& errors = *context.fErrors;
Ethan Nicholas371f6e12021-05-04 14:30:02 -040055 if (returnType.isArray()) {
Ethan Nicholas89cfde12021-09-27 11:20:34 -040056 errors.error(line, "functions may not return type '" + returnType.displayName() + "'");
Ethan Nicholas371f6e12021-05-04 14:30:02 -040057 return false;
58 }
59 if (context.fConfig->strictES2Mode() && returnType.isOrContainsArray()) {
Ethan Nicholas89cfde12021-09-27 11:20:34 -040060 errors.error(line, "functions may not return structs containing arrays");
Ethan Nicholas371f6e12021-05-04 14:30:02 -040061 return false;
62 }
63 if (!isBuiltin && !returnType.isVoid() && returnType.componentType().isOpaque()) {
Ethan Nicholas89cfde12021-09-27 11:20:34 -040064 errors.error(line, "functions may not return opaque type '" + returnType.displayName() +
Ethan Nicholas371f6e12021-05-04 14:30:02 -040065 "'");
66 return false;
67 }
68 return true;
69}
70
John Stiles0b822792021-05-04 17:41:53 -040071static bool check_parameters(const Context& context,
Ethan Nicholas371f6e12021-05-04 14:30:02 -040072 std::vector<std::unique_ptr<Variable>>& parameters, bool isMain,
73 bool isBuiltin) {
74 auto typeIsValidForColor = [&](const Type& type) {
75 return type == *context.fTypes.fHalf4 || type == *context.fTypes.fFloat4;
76 };
77
John Stiles9c19b9f2021-06-10 09:43:35 -040078 // The first color parameter passed to main() is the input color; the second is the dest color.
John Stiles50d0d092021-06-09 17:24:31 -040079 static constexpr int kBuiltinColorIDs[] = {SK_INPUT_COLOR_BUILTIN, SK_DEST_COLOR_BUILTIN};
80 unsigned int builtinColorIndex = 0;
81
John Stiles9c19b9f2021-06-10 09:43:35 -040082 // Check modifiers on each function parameter.
Ethan Nicholas371f6e12021-05-04 14:30:02 -040083 for (auto& param : parameters) {
Ethan Nicholas89cfde12021-09-27 11:20:34 -040084 IRGenerator::CheckModifiers(context, param->fLine, param->modifiers(),
Ethan Nicholas371f6e12021-05-04 14:30:02 -040085 Modifiers::kConst_Flag | Modifiers::kIn_Flag |
86 Modifiers::kOut_Flag, /*permittedLayoutFlags=*/0);
87 const Type& type = param->type();
88 // Only the (builtin) declarations of 'sample' are allowed to have shader/colorFilter or FP
89 // parameters. You can pass other opaque types to functions safely; this restriction is
90 // specific to "child" objects.
Brian Osman8c264792021-07-01 16:41:27 -040091 if (type.isEffectChild() && !isBuiltin) {
Ethan Nicholas89cfde12021-09-27 11:20:34 -040092 context.fErrors->error(param->fLine, "parameters of type '" + type.displayName() +
Ethan Nicholas8d116542021-08-11 13:27:16 -040093 "' not allowed");
Ethan Nicholas371f6e12021-05-04 14:30:02 -040094 return false;
95 }
96
97 Modifiers m = param->modifiers();
John Stilesbb2ef922021-07-26 08:32:07 -040098 if (isMain) {
John Stilesaddccaf2021-08-02 19:03:30 -040099 if (ProgramConfig::IsRuntimeEffect(context.fConfig->fKind)) {
John Stilesbb2ef922021-07-26 08:32:07 -0400100 // We verify that the signature is fully correct later. For now, if this is a
101 // runtime effect of any flavor, a float2 param is supposed to be the coords, and a
102 // half4/float parameter is supposed to be the input or destination color:
103 if (type == *context.fTypes.fFloat2) {
104 m.fLayout.fBuiltin = SK_MAIN_COORDS_BUILTIN;
105 } else if (typeIsValidForColor(type) &&
106 builtinColorIndex < SK_ARRAY_COUNT(kBuiltinColorIDs)) {
107 m.fLayout.fBuiltin = kBuiltinColorIDs[builtinColorIndex++];
108 }
109 if (m.fLayout.fBuiltin) {
110 param->setModifiers(context.fModifiersPool->add(m));
111 }
112 } else if (context.fConfig->fKind == ProgramKind::kFragment) {
113 // For testing purposes, we have .sksl inputs that are treated as both runtime
114 // effects and fragment shaders. To make that work, fragment shaders are allowed to
John Stiles9078a892021-08-18 15:03:17 -0400115 // have a coords parameter.
John Stilesbb2ef922021-07-26 08:32:07 -0400116 if (type == *context.fTypes.fFloat2) {
John Stiles9078a892021-08-18 15:03:17 -0400117 m.fLayout.fBuiltin = SK_MAIN_COORDS_BUILTIN;
John Stilesbb2ef922021-07-26 08:32:07 -0400118 param->setModifiers(context.fModifiersPool->add(m));
119 }
Ethan Nicholas371f6e12021-05-04 14:30:02 -0400120 }
121 }
122 }
123 return true;
124}
125
Ethan Nicholas89cfde12021-09-27 11:20:34 -0400126static bool check_main_signature(const Context& context, int line, const Type& returnType,
Ethan Nicholas371f6e12021-05-04 14:30:02 -0400127 std::vector<std::unique_ptr<Variable>>& parameters,
128 bool isBuiltin) {
Ethan Nicholas39f6da42021-08-23 13:10:07 -0400129 ErrorReporter& errors = *context.fErrors;
Ethan Nicholas371f6e12021-05-04 14:30:02 -0400130 ProgramKind kind = context.fConfig->fKind;
131
132 auto typeIsValidForColor = [&](const Type& type) {
133 return type == *context.fTypes.fHalf4 || type == *context.fTypes.fFloat4;
134 };
135
136 auto paramIsCoords = [&](int idx) {
137 const Variable& p = *parameters[idx];
138 return p.type() == *context.fTypes.fFloat2 &&
139 p.modifiers().fFlags == 0 &&
John Stiles9078a892021-08-18 15:03:17 -0400140 p.modifiers().fLayout.fBuiltin == SK_MAIN_COORDS_BUILTIN;
Ethan Nicholas371f6e12021-05-04 14:30:02 -0400141 };
142
John Stiles50d0d092021-06-09 17:24:31 -0400143 auto paramIsBuiltinColor = [&](int idx, int builtinID) {
144 const Variable& p = *parameters[idx];
145 return typeIsValidForColor(p.type()) &&
146 p.modifiers().fFlags == 0 &&
147 p.modifiers().fLayout.fBuiltin == builtinID;
Ethan Nicholas371f6e12021-05-04 14:30:02 -0400148 };
149
John Stiles50d0d092021-06-09 17:24:31 -0400150 auto paramIsInputColor = [&](int n) { return paramIsBuiltinColor(n, SK_INPUT_COLOR_BUILTIN); };
151 auto paramIsDestColor = [&](int n) { return paramIsBuiltinColor(n, SK_DEST_COLOR_BUILTIN); };
152
Ethan Nicholas371f6e12021-05-04 14:30:02 -0400153 switch (kind) {
154 case ProgramKind::kRuntimeColorFilter: {
155 // (half4|float4) main(half4|float4)
156 if (!typeIsValidForColor(returnType)) {
Ethan Nicholas89cfde12021-09-27 11:20:34 -0400157 errors.error(line, "'main' must return: 'vec4', 'float4', or 'half4'");
Ethan Nicholas371f6e12021-05-04 14:30:02 -0400158 return false;
159 }
160 bool validParams = (parameters.size() == 1 && paramIsInputColor(0));
161 if (!validParams) {
Ethan Nicholas89cfde12021-09-27 11:20:34 -0400162 errors.error(line, "'main' parameter must be 'vec4', 'float4', or 'half4'");
Ethan Nicholas371f6e12021-05-04 14:30:02 -0400163 return false;
164 }
165 break;
166 }
167 case ProgramKind::kRuntimeShader: {
168 // (half4|float4) main(float2) -or- (half4|float4) main(float2, half4|float4)
169 if (!typeIsValidForColor(returnType)) {
Ethan Nicholas89cfde12021-09-27 11:20:34 -0400170 errors.error(line, "'main' must return: 'vec4', 'float4', or 'half4'");
Ethan Nicholas371f6e12021-05-04 14:30:02 -0400171 return false;
172 }
173 bool validParams =
174 (parameters.size() == 1 && paramIsCoords(0)) ||
175 (parameters.size() == 2 && paramIsCoords(0) && paramIsInputColor(1));
176 if (!validParams) {
Ethan Nicholas89cfde12021-09-27 11:20:34 -0400177 errors.error(line, "'main' parameters must be (float2, (vec4|float4|half4)?)");
Ethan Nicholas371f6e12021-05-04 14:30:02 -0400178 return false;
179 }
180 break;
181 }
John Stiles2d8b8352021-06-16 11:33:13 -0400182 case ProgramKind::kRuntimeBlender: {
John Stilesf7f36ae2021-06-08 14:06:22 -0400183 // (half4|float4) main(half4|float4, half4|float4)
184 if (!typeIsValidForColor(returnType)) {
Ethan Nicholas89cfde12021-09-27 11:20:34 -0400185 errors.error(line, "'main' must return: 'vec4', 'float4', or 'half4'");
John Stilesf7f36ae2021-06-08 14:06:22 -0400186 return false;
187 }
188 if (!(parameters.size() == 2 &&
189 paramIsInputColor(0) &&
John Stiles50d0d092021-06-09 17:24:31 -0400190 paramIsDestColor(1))) {
Ethan Nicholas89cfde12021-09-27 11:20:34 -0400191 errors.error(line, "'main' parameters must be (vec4|float4|half4, "
John Stilesf7f36ae2021-06-08 14:06:22 -0400192 "vec4|float4|half4)");
193 return false;
194 }
195 break;
196 }
Ethan Nicholas371f6e12021-05-04 14:30:02 -0400197 case ProgramKind::kGeneric:
198 // No rules apply here
199 break;
200 case ProgramKind::kFragment: {
201 bool validParams = (parameters.size() == 0) ||
202 (parameters.size() == 1 && paramIsCoords(0));
203 if (!validParams) {
Ethan Nicholas89cfde12021-09-27 11:20:34 -0400204 errors.error(line, "shader 'main' must be main() or main(float2)");
Ethan Nicholas371f6e12021-05-04 14:30:02 -0400205 return false;
206 }
207 break;
208 }
209 case ProgramKind::kVertex:
Ethan Nicholas371f6e12021-05-04 14:30:02 -0400210 if (parameters.size()) {
Ethan Nicholas89cfde12021-09-27 11:20:34 -0400211 errors.error(line, "shader 'main' must have zero parameters");
Ethan Nicholas371f6e12021-05-04 14:30:02 -0400212 return false;
213 }
214 break;
215 }
216 return true;
217}
218
219/**
220 * Checks for a previously existing declaration of this function, reporting errors if there is an
221 * incompatible symbol. Returns true and sets outExistingDecl to point to the existing declaration
222 * (or null if none) on success, returns false on error.
223 */
Ethan Nicholas89cfde12021-09-27 11:20:34 -0400224static bool find_existing_declaration(const Context& context, SymbolTable& symbols, int line,
Ethan Nicholas962dec42021-06-10 13:06:39 -0400225 skstd::string_view name,
Ethan Nicholas371f6e12021-05-04 14:30:02 -0400226 std::vector<std::unique_ptr<Variable>>& parameters,
227 const Type* returnType, bool isBuiltin,
228 const FunctionDeclaration** outExistingDecl) {
Ethan Nicholas39f6da42021-08-23 13:10:07 -0400229 ErrorReporter& errors = *context.fErrors;
Ethan Nicholas371f6e12021-05-04 14:30:02 -0400230 const Symbol* entry = symbols[name];
231 *outExistingDecl = nullptr;
232 if (entry) {
233 std::vector<const FunctionDeclaration*> functions;
234 switch (entry->kind()) {
235 case Symbol::Kind::kUnresolvedFunction:
236 functions = entry->as<UnresolvedFunction>().functions();
237 break;
238 case Symbol::Kind::kFunctionDeclaration:
239 functions.push_back(&entry->as<FunctionDeclaration>());
240 break;
241 default:
Ethan Nicholas89cfde12021-09-27 11:20:34 -0400242 errors.error(line, "symbol '" + name + "' was already defined");
Ethan Nicholas371f6e12021-05-04 14:30:02 -0400243 return false;
244 }
245 for (const FunctionDeclaration* other : functions) {
246 SkASSERT(name == other->name());
247 if (parameters.size() != other->parameters().size()) {
248 continue;
249 }
250 bool match = true;
251 for (size_t i = 0; i < parameters.size(); i++) {
252 if (parameters[i]->type() != other->parameters()[i]->type()) {
253 match = false;
254 break;
255 }
256 }
257 if (!match) {
258 continue;
259 }
260 if (*returnType != other->returnType()) {
261 std::vector<const Variable*> paramPtrs;
262 paramPtrs.reserve(parameters.size());
263 for (std::unique_ptr<Variable>& param : parameters) {
264 paramPtrs.push_back(param.get());
265 }
Ethan Nicholas89cfde12021-09-27 11:20:34 -0400266 FunctionDeclaration invalidDecl(line,
Ethan Nicholas371f6e12021-05-04 14:30:02 -0400267 &other->modifiers(),
268 name,
269 std::move(paramPtrs),
270 returnType,
271 isBuiltin);
Ethan Nicholas89cfde12021-09-27 11:20:34 -0400272 errors.error(line,
Ethan Nicholas371f6e12021-05-04 14:30:02 -0400273 "functions '" + invalidDecl.description() + "' and '" +
274 other->description() + "' differ only in return type");
275 return false;
276 }
277 for (size_t i = 0; i < parameters.size(); i++) {
278 if (parameters[i]->modifiers() != other->parameters()[i]->modifiers()) {
Ethan Nicholas89cfde12021-09-27 11:20:34 -0400279 errors.error(line,
Ethan Nicholas371f6e12021-05-04 14:30:02 -0400280 "modifiers on parameter " + to_string((uint64_t)i + 1) +
281 " differ between declaration and definition");
282 return false;
283 }
284 }
285 if (other->definition() && !other->isBuiltin()) {
Ethan Nicholas89cfde12021-09-27 11:20:34 -0400286 errors.error(line, "duplicate definition of " + other->description());
Ethan Nicholas371f6e12021-05-04 14:30:02 -0400287 return false;
288 }
289 *outExistingDecl = other;
290 break;
291 }
292 }
293 return true;
294}
295
Ethan Nicholas89cfde12021-09-27 11:20:34 -0400296FunctionDeclaration::FunctionDeclaration(int line,
John Stilesf96cb712021-05-05 22:17:04 -0400297 const Modifiers* modifiers,
Ethan Nicholas962dec42021-06-10 13:06:39 -0400298 skstd::string_view name,
John Stilesf96cb712021-05-05 22:17:04 -0400299 std::vector<const Variable*> parameters,
300 const Type* returnType,
301 bool builtin)
Ethan Nicholas89cfde12021-09-27 11:20:34 -0400302 : INHERITED(line, kSymbolKind, name, /*type=*/nullptr)
John Stilesf96cb712021-05-05 22:17:04 -0400303 , fDefinition(nullptr)
304 , fModifiers(modifiers)
305 , fParameters(std::move(parameters))
306 , fReturnType(returnType)
307 , fBuiltin(builtin)
308 , fIsMain(name == "main")
John Stilesffc01892021-08-19 10:32:01 -0400309 , fIntrinsicKind(builtin ? identify_intrinsic(name) : kNotIntrinsic) {}
John Stilesf96cb712021-05-05 22:17:04 -0400310
Ethan Nicholas371f6e12021-05-04 14:30:02 -0400311const FunctionDeclaration* FunctionDeclaration::Convert(const Context& context,
Ethan Nicholas89cfde12021-09-27 11:20:34 -0400312 SymbolTable& symbols, int line, const Modifiers* modifiers,
Ethan Nicholas962dec42021-06-10 13:06:39 -0400313 skstd::string_view name, std::vector<std::unique_ptr<Variable>> parameters,
Ethan Nicholas371f6e12021-05-04 14:30:02 -0400314 const Type* returnType, bool isBuiltin) {
315 bool isMain = (name == "main");
316
317 const FunctionDeclaration* decl = nullptr;
Ethan Nicholas89cfde12021-09-27 11:20:34 -0400318 if (!check_modifiers(context, line, *modifiers, isBuiltin) ||
319 !check_return_type(context, line, *returnType, isBuiltin) ||
John Stiles0b822792021-05-04 17:41:53 -0400320 !check_parameters(context, parameters, isMain, isBuiltin) ||
Ethan Nicholas89cfde12021-09-27 11:20:34 -0400321 (isMain && !check_main_signature(context, line, *returnType, parameters, isBuiltin)) ||
322 !find_existing_declaration(context, symbols, line, name, parameters, returnType,
Ethan Nicholas371f6e12021-05-04 14:30:02 -0400323 isBuiltin, &decl)) {
324 return nullptr;
325 }
326 std::vector<const Variable*> finalParameters;
327 finalParameters.reserve(parameters.size());
John Stilesf96cb712021-05-05 22:17:04 -0400328 for (std::unique_ptr<Variable>& param : parameters) {
Ethan Nicholas371f6e12021-05-04 14:30:02 -0400329 finalParameters.push_back(symbols.takeOwnershipOfSymbol(std::move(param)));
330 }
331 if (decl) {
332 return decl;
333 }
Ethan Nicholas89cfde12021-09-27 11:20:34 -0400334 auto result = std::make_unique<FunctionDeclaration>(line, modifiers, name,
Ethan Nicholas371f6e12021-05-04 14:30:02 -0400335 std::move(finalParameters), returnType,
336 isBuiltin);
337 return symbols.add(std::move(result));
338}
339
John Stilesf96cb712021-05-05 22:17:04 -0400340String FunctionDeclaration::mangledName() const {
341 if ((this->isBuiltin() && !this->definition()) || this->isMain()) {
342 // Builtins without a definition (like `sin` or `sqrt`) must use their real names.
Ethan Nicholasd2e09602021-06-10 11:21:59 -0400343 return String(this->name());
John Stilesf96cb712021-05-05 22:17:04 -0400344 }
345 // GLSL forbids two underscores in a row; add an extra character if necessary to avoid this.
Ethan Nicholasd2e09602021-06-10 11:21:59 -0400346 const char* splitter = this->name().ends_with("_") ? "x_" : "_";
John Stilesf96cb712021-05-05 22:17:04 -0400347 // Rename function to `funcname_returntypeparamtypes`.
348 String result = this->name() + splitter + this->returnType().abbreviatedName();
349 for (const Variable* p : this->parameters()) {
350 result += p->type().abbreviatedName();
351 }
352 return result;
353}
354
355String FunctionDeclaration::description() const {
356 String result = this->returnType().displayName() + " " + this->name() + "(";
357 String separator;
358 for (const Variable* p : this->parameters()) {
359 result += separator;
360 separator = ", ";
361 result += p->type().displayName();
362 result += " ";
363 result += p->name();
364 }
365 result += ")";
366 return result;
367}
368
369bool FunctionDeclaration::matches(const FunctionDeclaration& f) const {
370 if (this->name() != f.name()) {
371 return false;
372 }
373 const std::vector<const Variable*>& parameters = this->parameters();
374 const std::vector<const Variable*>& otherParameters = f.parameters();
375 if (parameters.size() != otherParameters.size()) {
376 return false;
377 }
378 for (size_t i = 0; i < parameters.size(); i++) {
379 if (parameters[i]->type() != otherParameters[i]->type()) {
380 return false;
381 }
382 }
383 return true;
384}
385
386bool FunctionDeclaration::determineFinalTypes(const ExpressionArray& arguments,
387 ParamTypes* outParameterTypes,
388 const Type** outReturnType) const {
389 const std::vector<const Variable*>& parameters = this->parameters();
390 SkASSERT(arguments.size() == parameters.size());
391
392 outParameterTypes->reserve_back(arguments.size());
393 int genericIndex = -1;
394 for (size_t i = 0; i < arguments.size(); i++) {
395 // Non-generic parameters are final as-is.
396 const Type& parameterType = parameters[i]->type();
397 if (parameterType.typeKind() != Type::TypeKind::kGeneric) {
398 outParameterTypes->push_back(&parameterType);
399 continue;
400 }
401 // We use the first generic parameter we find to lock in the generic index;
402 // e.g. if we find `float3` here, all `$genType`s will be assumed to be `float3`.
403 const std::vector<const Type*>& types = parameterType.coercibleTypes();
404 if (genericIndex == -1) {
405 for (size_t j = 0; j < types.size(); j++) {
406 if (arguments[i]->type().canCoerceTo(*types[j], /*allowNarrowing=*/true)) {
407 genericIndex = j;
408 break;
409 }
410 }
411 if (genericIndex == -1) {
412 // The passed-in type wasn't a match for ANY of the generic possibilities.
413 // This function isn't a match at all.
414 return false;
415 }
416 }
417 outParameterTypes->push_back(types[genericIndex]);
418 }
419 // Apply the generic index to our return type.
420 const Type& returnType = this->returnType();
421 if (returnType.typeKind() == Type::TypeKind::kGeneric) {
422 if (genericIndex == -1) {
423 // We don't support functions with a generic return type and no other generics.
424 return false;
425 }
426 *outReturnType = returnType.coercibleTypes()[genericIndex];
427 } else {
428 *outReturnType = &returnType;
429 }
430 return true;
431}
432
Ethan Nicholas371f6e12021-05-04 14:30:02 -0400433} // namespace SkSL