blob: 7892947e20c39afce9d4e457f5af1991785ffd06 [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 Stilesf96cb712021-05-05 22:17:04 -040016static IntrinsicKind identify_intrinsic(const String& functionName) {
17 #define SKSL_INTRINSIC(name) {#name, k_##name##_IntrinsicKind},
18 static const auto* kAllIntrinsics = new std::unordered_map<String, IntrinsicKind>{
19 SKSL_INTRINSIC_LIST
20 };
21 #undef SKSL_INTRINSIC
22
23 auto iter = kAllIntrinsics->find(functionName);
24 if (iter != kAllIntrinsics->end()) {
25 return iter->second;
26 }
27
28 return kNotIntrinsic;
29}
30
John Stilesefde90d2021-08-12 23:06:24 -040031static bool check_modifiers(const Context& context,
32 int offset,
33 const Modifiers& modifiers,
34 bool isBuiltin) {
35 const int permitted = Modifiers::kHasSideEffects_Flag |
36 Modifiers::kInline_Flag |
37 Modifiers::kNoInline_Flag |
38 (isBuiltin ? Modifiers::kES3_Flag : 0);
39 IRGenerator::CheckModifiers(context, offset, modifiers, permitted, /*permittedLayoutFlags=*/0);
Ethan Nicholas371f6e12021-05-04 14:30:02 -040040 if ((modifiers.fFlags & Modifiers::kInline_Flag) &&
41 (modifiers.fFlags & Modifiers::kNoInline_Flag)) {
Ethan Nicholas8d116542021-08-11 13:27:16 -040042 context.errors().error(offset, "functions cannot be both 'inline' and 'noinline'");
Ethan Nicholas371f6e12021-05-04 14:30:02 -040043 return false;
44 }
45 return true;
46}
47
48static bool check_return_type(const Context& context, int offset, const Type& returnType,
49 bool isBuiltin) {
Ethan Nicholas8d116542021-08-11 13:27:16 -040050 ErrorReporter& errors = context.errors();
Ethan Nicholas371f6e12021-05-04 14:30:02 -040051 if (returnType.isArray()) {
52 errors.error(offset, "functions may not return type '" + returnType.displayName() + "'");
53 return false;
54 }
55 if (context.fConfig->strictES2Mode() && returnType.isOrContainsArray()) {
56 errors.error(offset, "functions may not return structs containing arrays");
57 return false;
58 }
59 if (!isBuiltin && !returnType.isVoid() && returnType.componentType().isOpaque()) {
60 errors.error(offset, "functions may not return opaque type '" + returnType.displayName() +
61 "'");
62 return false;
63 }
64 return true;
65}
66
John Stiles0b822792021-05-04 17:41:53 -040067static bool check_parameters(const Context& context,
Ethan Nicholas371f6e12021-05-04 14:30:02 -040068 std::vector<std::unique_ptr<Variable>>& parameters, bool isMain,
69 bool isBuiltin) {
70 auto typeIsValidForColor = [&](const Type& type) {
71 return type == *context.fTypes.fHalf4 || type == *context.fTypes.fFloat4;
72 };
73
John Stiles9c19b9f2021-06-10 09:43:35 -040074 // The first color parameter passed to main() is the input color; the second is the dest color.
John Stiles50d0d092021-06-09 17:24:31 -040075 static constexpr int kBuiltinColorIDs[] = {SK_INPUT_COLOR_BUILTIN, SK_DEST_COLOR_BUILTIN};
76 unsigned int builtinColorIndex = 0;
77
John Stiles9c19b9f2021-06-10 09:43:35 -040078 // Check modifiers on each function parameter.
Ethan Nicholas371f6e12021-05-04 14:30:02 -040079 for (auto& param : parameters) {
80 IRGenerator::CheckModifiers(context, param->fOffset, param->modifiers(),
81 Modifiers::kConst_Flag | Modifiers::kIn_Flag |
82 Modifiers::kOut_Flag, /*permittedLayoutFlags=*/0);
83 const Type& type = param->type();
84 // Only the (builtin) declarations of 'sample' are allowed to have shader/colorFilter or FP
85 // parameters. You can pass other opaque types to functions safely; this restriction is
86 // specific to "child" objects.
Brian Osman8c264792021-07-01 16:41:27 -040087 if (type.isEffectChild() && !isBuiltin) {
Ethan Nicholas8d116542021-08-11 13:27:16 -040088 context.errors().error(param->fOffset, "parameters of type '" + type.displayName() +
89 "' not allowed");
Ethan Nicholas371f6e12021-05-04 14:30:02 -040090 return false;
91 }
92
93 Modifiers m = param->modifiers();
John Stilesbb2ef922021-07-26 08:32:07 -040094 if (isMain) {
John Stilesaddccaf2021-08-02 19:03:30 -040095 if (ProgramConfig::IsRuntimeEffect(context.fConfig->fKind)) {
John Stilesbb2ef922021-07-26 08:32:07 -040096 // We verify that the signature is fully correct later. For now, if this is a
97 // runtime effect of any flavor, a float2 param is supposed to be the coords, and a
98 // half4/float parameter is supposed to be the input or destination color:
99 if (type == *context.fTypes.fFloat2) {
100 m.fLayout.fBuiltin = SK_MAIN_COORDS_BUILTIN;
101 } else if (typeIsValidForColor(type) &&
102 builtinColorIndex < SK_ARRAY_COUNT(kBuiltinColorIDs)) {
103 m.fLayout.fBuiltin = kBuiltinColorIDs[builtinColorIndex++];
104 }
105 if (m.fLayout.fBuiltin) {
106 param->setModifiers(context.fModifiersPool->add(m));
107 }
108 } else if (context.fConfig->fKind == ProgramKind::kFragment) {
109 // For testing purposes, we have .sksl inputs that are treated as both runtime
110 // effects and fragment shaders. To make that work, fragment shaders are allowed to
111 // have a coords parameter. We turn it into sk_FragCoord.
112 if (type == *context.fTypes.fFloat2) {
113 m.fLayout.fBuiltin = SK_FRAGCOORD_BUILTIN;
114 param->setModifiers(context.fModifiersPool->add(m));
115 }
Ethan Nicholas371f6e12021-05-04 14:30:02 -0400116 }
117 }
118 }
119 return true;
120}
121
122static bool check_main_signature(const Context& context, int offset, const Type& returnType,
123 std::vector<std::unique_ptr<Variable>>& parameters,
124 bool isBuiltin) {
Ethan Nicholas8d116542021-08-11 13:27:16 -0400125 ErrorReporter& errors = context.errors();
Ethan Nicholas371f6e12021-05-04 14:30:02 -0400126 ProgramKind kind = context.fConfig->fKind;
127
128 auto typeIsValidForColor = [&](const Type& type) {
129 return type == *context.fTypes.fHalf4 || type == *context.fTypes.fFloat4;
130 };
131
132 auto paramIsCoords = [&](int idx) {
133 const Variable& p = *parameters[idx];
134 return p.type() == *context.fTypes.fFloat2 &&
135 p.modifiers().fFlags == 0 &&
136 p.modifiers().fLayout.fBuiltin == (kind == ProgramKind::kFragment
137 ? SK_FRAGCOORD_BUILTIN
138 : SK_MAIN_COORDS_BUILTIN);
139 };
140
John Stiles50d0d092021-06-09 17:24:31 -0400141 auto paramIsBuiltinColor = [&](int idx, int builtinID) {
142 const Variable& p = *parameters[idx];
143 return typeIsValidForColor(p.type()) &&
144 p.modifiers().fFlags == 0 &&
145 p.modifiers().fLayout.fBuiltin == builtinID;
Ethan Nicholas371f6e12021-05-04 14:30:02 -0400146 };
147
John Stiles50d0d092021-06-09 17:24:31 -0400148 auto paramIsInputColor = [&](int n) { return paramIsBuiltinColor(n, SK_INPUT_COLOR_BUILTIN); };
149 auto paramIsDestColor = [&](int n) { return paramIsBuiltinColor(n, SK_DEST_COLOR_BUILTIN); };
150
Ethan Nicholas371f6e12021-05-04 14:30:02 -0400151 switch (kind) {
152 case ProgramKind::kRuntimeColorFilter: {
153 // (half4|float4) main(half4|float4)
154 if (!typeIsValidForColor(returnType)) {
155 errors.error(offset, "'main' must return: 'vec4', 'float4', or 'half4'");
156 return false;
157 }
158 bool validParams = (parameters.size() == 1 && paramIsInputColor(0));
159 if (!validParams) {
160 errors.error(offset, "'main' parameter must be 'vec4', 'float4', or 'half4'");
161 return false;
162 }
163 break;
164 }
165 case ProgramKind::kRuntimeShader: {
166 // (half4|float4) main(float2) -or- (half4|float4) main(float2, half4|float4)
167 if (!typeIsValidForColor(returnType)) {
168 errors.error(offset, "'main' must return: 'vec4', 'float4', or 'half4'");
169 return false;
170 }
171 bool validParams =
172 (parameters.size() == 1 && paramIsCoords(0)) ||
173 (parameters.size() == 2 && paramIsCoords(0) && paramIsInputColor(1));
174 if (!validParams) {
175 errors.error(offset, "'main' parameters must be (float2, (vec4|float4|half4)?)");
176 return false;
177 }
178 break;
179 }
John Stiles2d8b8352021-06-16 11:33:13 -0400180 case ProgramKind::kRuntimeBlender: {
John Stilesf7f36ae2021-06-08 14:06:22 -0400181 // (half4|float4) main(half4|float4, half4|float4)
182 if (!typeIsValidForColor(returnType)) {
183 errors.error(offset, "'main' must return: 'vec4', 'float4', or 'half4'");
184 return false;
185 }
186 if (!(parameters.size() == 2 &&
187 paramIsInputColor(0) &&
John Stiles50d0d092021-06-09 17:24:31 -0400188 paramIsDestColor(1))) {
John Stilesf7f36ae2021-06-08 14:06:22 -0400189 errors.error(offset, "'main' parameters must be (vec4|float4|half4, "
190 "vec4|float4|half4)");
191 return false;
192 }
193 break;
194 }
Ethan Nicholas371f6e12021-05-04 14:30:02 -0400195 case ProgramKind::kGeneric:
196 // No rules apply here
197 break;
198 case ProgramKind::kFragment: {
199 bool validParams = (parameters.size() == 0) ||
200 (parameters.size() == 1 && paramIsCoords(0));
201 if (!validParams) {
202 errors.error(offset, "shader 'main' must be main() or main(float2)");
203 return false;
204 }
205 break;
206 }
207 case ProgramKind::kVertex:
208 case ProgramKind::kGeometry:
209 if (parameters.size()) {
210 errors.error(offset, "shader 'main' must have zero parameters");
211 return false;
212 }
213 break;
214 }
215 return true;
216}
217
218/**
219 * Checks for a previously existing declaration of this function, reporting errors if there is an
220 * incompatible symbol. Returns true and sets outExistingDecl to point to the existing declaration
221 * (or null if none) on success, returns false on error.
222 */
223static bool find_existing_declaration(const Context& context, SymbolTable& symbols, int offset,
Ethan Nicholas962dec42021-06-10 13:06:39 -0400224 skstd::string_view name,
Ethan Nicholas371f6e12021-05-04 14:30:02 -0400225 std::vector<std::unique_ptr<Variable>>& parameters,
226 const Type* returnType, bool isBuiltin,
227 const FunctionDeclaration** outExistingDecl) {
Ethan Nicholas8d116542021-08-11 13:27:16 -0400228 ErrorReporter& errors = context.errors();
Ethan Nicholas371f6e12021-05-04 14:30:02 -0400229 const Symbol* entry = symbols[name];
230 *outExistingDecl = nullptr;
231 if (entry) {
232 std::vector<const FunctionDeclaration*> functions;
233 switch (entry->kind()) {
234 case Symbol::Kind::kUnresolvedFunction:
235 functions = entry->as<UnresolvedFunction>().functions();
236 break;
237 case Symbol::Kind::kFunctionDeclaration:
238 functions.push_back(&entry->as<FunctionDeclaration>());
239 break;
240 default:
241 errors.error(offset, "symbol '" + name + "' was already defined");
242 return false;
243 }
244 for (const FunctionDeclaration* other : functions) {
245 SkASSERT(name == other->name());
246 if (parameters.size() != other->parameters().size()) {
247 continue;
248 }
249 bool match = true;
250 for (size_t i = 0; i < parameters.size(); i++) {
251 if (parameters[i]->type() != other->parameters()[i]->type()) {
252 match = false;
253 break;
254 }
255 }
256 if (!match) {
257 continue;
258 }
259 if (*returnType != other->returnType()) {
260 std::vector<const Variable*> paramPtrs;
261 paramPtrs.reserve(parameters.size());
262 for (std::unique_ptr<Variable>& param : parameters) {
263 paramPtrs.push_back(param.get());
264 }
265 FunctionDeclaration invalidDecl(offset,
266 &other->modifiers(),
267 name,
268 std::move(paramPtrs),
269 returnType,
270 isBuiltin);
271 errors.error(offset,
272 "functions '" + invalidDecl.description() + "' and '" +
273 other->description() + "' differ only in return type");
274 return false;
275 }
276 for (size_t i = 0; i < parameters.size(); i++) {
277 if (parameters[i]->modifiers() != other->parameters()[i]->modifiers()) {
278 errors.error(offset,
279 "modifiers on parameter " + to_string((uint64_t)i + 1) +
280 " differ between declaration and definition");
281 return false;
282 }
283 }
284 if (other->definition() && !other->isBuiltin()) {
285 errors.error(offset, "duplicate definition of " + other->description());
286 return false;
287 }
288 *outExistingDecl = other;
289 break;
290 }
291 }
292 return true;
293}
294
John Stilesf96cb712021-05-05 22:17:04 -0400295FunctionDeclaration::FunctionDeclaration(int offset,
296 const Modifiers* modifiers,
Ethan Nicholas962dec42021-06-10 13:06:39 -0400297 skstd::string_view name,
John Stilesf96cb712021-05-05 22:17:04 -0400298 std::vector<const Variable*> parameters,
299 const Type* returnType,
300 bool builtin)
301 : INHERITED(offset, kSymbolKind, name, /*type=*/nullptr)
302 , fDefinition(nullptr)
303 , fModifiers(modifiers)
304 , fParameters(std::move(parameters))
305 , fReturnType(returnType)
306 , fBuiltin(builtin)
307 , fIsMain(name == "main")
Ethan Nicholasd2e09602021-06-10 11:21:59 -0400308 , fIntrinsicKind(builtin ? identify_intrinsic(String(name)) : kNotIntrinsic) {}
John Stilesf96cb712021-05-05 22:17:04 -0400309
Ethan Nicholas371f6e12021-05-04 14:30:02 -0400310const FunctionDeclaration* FunctionDeclaration::Convert(const Context& context,
John Stiles0b822792021-05-04 17:41:53 -0400311 SymbolTable& symbols, int offset, const Modifiers* modifiers,
Ethan Nicholas962dec42021-06-10 13:06:39 -0400312 skstd::string_view name, std::vector<std::unique_ptr<Variable>> parameters,
Ethan Nicholas371f6e12021-05-04 14:30:02 -0400313 const Type* returnType, bool isBuiltin) {
314 bool isMain = (name == "main");
315
316 const FunctionDeclaration* decl = nullptr;
John Stilesefde90d2021-08-12 23:06:24 -0400317 if (!check_modifiers(context, offset, *modifiers, isBuiltin) ||
Ethan Nicholas371f6e12021-05-04 14:30:02 -0400318 !check_return_type(context, offset, *returnType, isBuiltin) ||
John Stiles0b822792021-05-04 17:41:53 -0400319 !check_parameters(context, parameters, isMain, isBuiltin) ||
Ethan Nicholas371f6e12021-05-04 14:30:02 -0400320 (isMain && !check_main_signature(context, offset, *returnType, parameters, isBuiltin)) ||
321 !find_existing_declaration(context, symbols, offset, name, parameters, returnType,
322 isBuiltin, &decl)) {
323 return nullptr;
324 }
325 std::vector<const Variable*> finalParameters;
326 finalParameters.reserve(parameters.size());
John Stilesf96cb712021-05-05 22:17:04 -0400327 for (std::unique_ptr<Variable>& param : parameters) {
Ethan Nicholas371f6e12021-05-04 14:30:02 -0400328 finalParameters.push_back(symbols.takeOwnershipOfSymbol(std::move(param)));
329 }
330 if (decl) {
331 return decl;
332 }
333 auto result = std::make_unique<FunctionDeclaration>(offset, modifiers, name,
334 std::move(finalParameters), returnType,
335 isBuiltin);
336 return symbols.add(std::move(result));
337}
338
John Stilesf96cb712021-05-05 22:17:04 -0400339String FunctionDeclaration::mangledName() const {
340 if ((this->isBuiltin() && !this->definition()) || this->isMain()) {
341 // Builtins without a definition (like `sin` or `sqrt`) must use their real names.
Ethan Nicholasd2e09602021-06-10 11:21:59 -0400342 return String(this->name());
John Stilesf96cb712021-05-05 22:17:04 -0400343 }
344 // GLSL forbids two underscores in a row; add an extra character if necessary to avoid this.
Ethan Nicholasd2e09602021-06-10 11:21:59 -0400345 const char* splitter = this->name().ends_with("_") ? "x_" : "_";
John Stilesf96cb712021-05-05 22:17:04 -0400346 // Rename function to `funcname_returntypeparamtypes`.
347 String result = this->name() + splitter + this->returnType().abbreviatedName();
348 for (const Variable* p : this->parameters()) {
349 result += p->type().abbreviatedName();
350 }
351 return result;
352}
353
354String FunctionDeclaration::description() const {
355 String result = this->returnType().displayName() + " " + this->name() + "(";
356 String separator;
357 for (const Variable* p : this->parameters()) {
358 result += separator;
359 separator = ", ";
360 result += p->type().displayName();
361 result += " ";
362 result += p->name();
363 }
364 result += ")";
365 return result;
366}
367
368bool FunctionDeclaration::matches(const FunctionDeclaration& f) const {
369 if (this->name() != f.name()) {
370 return false;
371 }
372 const std::vector<const Variable*>& parameters = this->parameters();
373 const std::vector<const Variable*>& otherParameters = f.parameters();
374 if (parameters.size() != otherParameters.size()) {
375 return false;
376 }
377 for (size_t i = 0; i < parameters.size(); i++) {
378 if (parameters[i]->type() != otherParameters[i]->type()) {
379 return false;
380 }
381 }
382 return true;
383}
384
385bool FunctionDeclaration::determineFinalTypes(const ExpressionArray& arguments,
386 ParamTypes* outParameterTypes,
387 const Type** outReturnType) const {
388 const std::vector<const Variable*>& parameters = this->parameters();
389 SkASSERT(arguments.size() == parameters.size());
390
391 outParameterTypes->reserve_back(arguments.size());
392 int genericIndex = -1;
393 for (size_t i = 0; i < arguments.size(); i++) {
394 // Non-generic parameters are final as-is.
395 const Type& parameterType = parameters[i]->type();
396 if (parameterType.typeKind() != Type::TypeKind::kGeneric) {
397 outParameterTypes->push_back(&parameterType);
398 continue;
399 }
400 // We use the first generic parameter we find to lock in the generic index;
401 // e.g. if we find `float3` here, all `$genType`s will be assumed to be `float3`.
402 const std::vector<const Type*>& types = parameterType.coercibleTypes();
403 if (genericIndex == -1) {
404 for (size_t j = 0; j < types.size(); j++) {
405 if (arguments[i]->type().canCoerceTo(*types[j], /*allowNarrowing=*/true)) {
406 genericIndex = j;
407 break;
408 }
409 }
410 if (genericIndex == -1) {
411 // The passed-in type wasn't a match for ANY of the generic possibilities.
412 // This function isn't a match at all.
413 return false;
414 }
415 }
416 outParameterTypes->push_back(types[genericIndex]);
417 }
418 // Apply the generic index to our return type.
419 const Type& returnType = this->returnType();
420 if (returnType.typeKind() == Type::TypeKind::kGeneric) {
421 if (genericIndex == -1) {
422 // We don't support functions with a generic return type and no other generics.
423 return false;
424 }
425 *outReturnType = returnType.coercibleTypes()[genericIndex];
426 } else {
427 *outReturnType = &returnType;
428 }
429 return true;
430}
431
Ethan Nicholas371f6e12021-05-04 14:30:02 -0400432} // namespace SkSL