blob: 29f8b541cf4dbace165a572f7ab2433f60bde716 [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
Ethan Nicholas371f6e12021-05-04 14:30:02 -040031static bool check_modifiers(const Context& context, int offset, const Modifiers& modifiers) {
32 IRGenerator::CheckModifiers(
33 context,
34 offset,
35 modifiers,
36 Modifiers::kHasSideEffects_Flag | Modifiers::kInline_Flag | Modifiers::kNoInline_Flag,
37 /*permittedLayoutFlags=*/0);
38 if ((modifiers.fFlags & Modifiers::kInline_Flag) &&
39 (modifiers.fFlags & Modifiers::kNoInline_Flag)) {
40 context.fErrors.error(offset, "functions cannot be both 'inline' and 'noinline'");
41 return false;
42 }
43 return true;
44}
45
46static bool check_return_type(const Context& context, int offset, const Type& returnType,
47 bool isBuiltin) {
48 ErrorReporter& errors = context.fErrors;
49 if (returnType.isArray()) {
50 errors.error(offset, "functions may not return type '" + returnType.displayName() + "'");
51 return false;
52 }
53 if (context.fConfig->strictES2Mode() && returnType.isOrContainsArray()) {
54 errors.error(offset, "functions may not return structs containing arrays");
55 return false;
56 }
57 if (!isBuiltin && !returnType.isVoid() && returnType.componentType().isOpaque()) {
58 errors.error(offset, "functions may not return opaque type '" + returnType.displayName() +
59 "'");
60 return false;
61 }
62 return true;
63}
64
John Stiles0b822792021-05-04 17:41:53 -040065static bool check_parameters(const Context& context,
Ethan Nicholas371f6e12021-05-04 14:30:02 -040066 std::vector<std::unique_ptr<Variable>>& parameters, bool isMain,
67 bool isBuiltin) {
68 auto typeIsValidForColor = [&](const Type& type) {
69 return type == *context.fTypes.fHalf4 || type == *context.fTypes.fFloat4;
70 };
71
John Stiles9c19b9f2021-06-10 09:43:35 -040072 // The first color parameter passed to main() is the input color; the second is the dest color.
John Stiles50d0d092021-06-09 17:24:31 -040073 static constexpr int kBuiltinColorIDs[] = {SK_INPUT_COLOR_BUILTIN, SK_DEST_COLOR_BUILTIN};
74 unsigned int builtinColorIndex = 0;
75
John Stiles9c19b9f2021-06-10 09:43:35 -040076 // Check modifiers on each function parameter.
Ethan Nicholas371f6e12021-05-04 14:30:02 -040077 for (auto& param : parameters) {
78 IRGenerator::CheckModifiers(context, param->fOffset, param->modifiers(),
79 Modifiers::kConst_Flag | Modifiers::kIn_Flag |
80 Modifiers::kOut_Flag, /*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() || type.isFragmentProcessor()) && !isBuiltin) {
86 context.fErrors.error(param->fOffset, "parameters of type '" + type.displayName() +
87 "' not allowed");
88 return false;
89 }
90
91 Modifiers m = param->modifiers();
92 ProgramKind kind = context.fConfig->fKind;
93 if (isMain && (kind == ProgramKind::kRuntimeColorFilter ||
94 kind == ProgramKind::kRuntimeShader ||
John Stiles2d8b8352021-06-16 11:33:13 -040095 kind == ProgramKind::kRuntimeBlender ||
Ethan Nicholas371f6e12021-05-04 14:30:02 -040096 kind == ProgramKind::kFragmentProcessor)) {
97 // We verify that the signature is fully correct later. For now, if this is an .fp or
98 // runtime effect of any flavor, a float2 param is supposed to be the coords, and
John Stiles50d0d092021-06-09 17:24:31 -040099 // a half4/float parameter is supposed to be the input or destination color:
Ethan Nicholas371f6e12021-05-04 14:30:02 -0400100 if (type == *context.fTypes.fFloat2) {
101 m.fLayout.fBuiltin = SK_MAIN_COORDS_BUILTIN;
John Stiles9c19b9f2021-06-10 09:43:35 -0400102 } else if (typeIsValidForColor(type) &&
103 builtinColorIndex < SK_ARRAY_COUNT(kBuiltinColorIDs)) {
John Stiles50d0d092021-06-09 17:24:31 -0400104 m.fLayout.fBuiltin = kBuiltinColorIDs[builtinColorIndex++];
Ethan Nicholas371f6e12021-05-04 14:30:02 -0400105 }
106 if (m.fLayout.fBuiltin) {
John Stiles0b822792021-05-04 17:41:53 -0400107 param->setModifiers(context.fModifiersPool->add(m));
Ethan Nicholas371f6e12021-05-04 14:30:02 -0400108 }
109 }
110 if (isMain && (kind == ProgramKind::kFragment)) {
111 // For testing purposes, we have .sksl inputs that are treated as both runtime effects
112 // and fragment shaders. To make that work, fragment shaders are allowed to have a
113 // coords parameter. We turn it into sk_FragCoord.
114 if (type == *context.fTypes.fFloat2) {
115 m.fLayout.fBuiltin = SK_FRAGCOORD_BUILTIN;
John Stiles0b822792021-05-04 17:41:53 -0400116 param->setModifiers(context.fModifiersPool->add(m));
Ethan Nicholas371f6e12021-05-04 14:30:02 -0400117 }
118 }
119 }
120 return true;
121}
122
123static bool check_main_signature(const Context& context, int offset, const Type& returnType,
124 std::vector<std::unique_ptr<Variable>>& parameters,
125 bool isBuiltin) {
126 ErrorReporter& errors = context.fErrors;
127 ProgramKind kind = context.fConfig->fKind;
128
129 auto typeIsValidForColor = [&](const Type& type) {
130 return type == *context.fTypes.fHalf4 || type == *context.fTypes.fFloat4;
131 };
132
133 auto paramIsCoords = [&](int idx) {
134 const Variable& p = *parameters[idx];
135 return p.type() == *context.fTypes.fFloat2 &&
136 p.modifiers().fFlags == 0 &&
137 p.modifiers().fLayout.fBuiltin == (kind == ProgramKind::kFragment
138 ? SK_FRAGCOORD_BUILTIN
139 : SK_MAIN_COORDS_BUILTIN);
140 };
141
John Stiles50d0d092021-06-09 17:24:31 -0400142 auto paramIsBuiltinColor = [&](int idx, int builtinID) {
143 const Variable& p = *parameters[idx];
144 return typeIsValidForColor(p.type()) &&
145 p.modifiers().fFlags == 0 &&
146 p.modifiers().fLayout.fBuiltin == builtinID;
Ethan Nicholas371f6e12021-05-04 14:30:02 -0400147 };
148
John Stiles50d0d092021-06-09 17:24:31 -0400149 auto paramIsInputColor = [&](int n) { return paramIsBuiltinColor(n, SK_INPUT_COLOR_BUILTIN); };
150 auto paramIsDestColor = [&](int n) { return paramIsBuiltinColor(n, SK_DEST_COLOR_BUILTIN); };
151
Ethan Nicholas371f6e12021-05-04 14:30:02 -0400152 switch (kind) {
153 case ProgramKind::kRuntimeColorFilter: {
154 // (half4|float4) main(half4|float4)
155 if (!typeIsValidForColor(returnType)) {
156 errors.error(offset, "'main' must return: 'vec4', 'float4', or 'half4'");
157 return false;
158 }
159 bool validParams = (parameters.size() == 1 && paramIsInputColor(0));
160 if (!validParams) {
161 errors.error(offset, "'main' parameter must be 'vec4', 'float4', or 'half4'");
162 return false;
163 }
164 break;
165 }
166 case ProgramKind::kRuntimeShader: {
167 // (half4|float4) main(float2) -or- (half4|float4) main(float2, half4|float4)
168 if (!typeIsValidForColor(returnType)) {
169 errors.error(offset, "'main' must return: 'vec4', 'float4', or 'half4'");
170 return false;
171 }
172 bool validParams =
173 (parameters.size() == 1 && paramIsCoords(0)) ||
174 (parameters.size() == 2 && paramIsCoords(0) && paramIsInputColor(1));
175 if (!validParams) {
176 errors.error(offset, "'main' parameters must be (float2, (vec4|float4|half4)?)");
177 return false;
178 }
179 break;
180 }
John Stiles2d8b8352021-06-16 11:33:13 -0400181 case ProgramKind::kRuntimeBlender: {
John Stilesf7f36ae2021-06-08 14:06:22 -0400182 // (half4|float4) main(half4|float4, half4|float4)
183 if (!typeIsValidForColor(returnType)) {
184 errors.error(offset, "'main' must return: 'vec4', 'float4', or 'half4'");
185 return false;
186 }
187 if (!(parameters.size() == 2 &&
188 paramIsInputColor(0) &&
John Stiles50d0d092021-06-09 17:24:31 -0400189 paramIsDestColor(1))) {
John Stilesf7f36ae2021-06-08 14:06:22 -0400190 errors.error(offset, "'main' parameters must be (vec4|float4|half4, "
191 "vec4|float4|half4)");
192 return false;
193 }
194 break;
195 }
Ethan Nicholas371f6e12021-05-04 14:30:02 -0400196 case ProgramKind::kFragmentProcessor: {
197 if (returnType != *context.fTypes.fHalf4) {
198 errors.error(offset, ".fp 'main' must return 'half4'");
199 return false;
200 }
201 bool validParams = (parameters.size() == 0) ||
202 (parameters.size() == 1 && paramIsCoords(0));
203 if (!validParams) {
204 errors.error(offset, ".fp 'main' must be declared main() or main(float2)");
205 return false;
206 }
207 break;
208 }
209 case ProgramKind::kGeneric:
210 // No rules apply here
211 break;
212 case ProgramKind::kFragment: {
213 bool validParams = (parameters.size() == 0) ||
214 (parameters.size() == 1 && paramIsCoords(0));
215 if (!validParams) {
216 errors.error(offset, "shader 'main' must be main() or main(float2)");
217 return false;
218 }
219 break;
220 }
221 case ProgramKind::kVertex:
222 case ProgramKind::kGeometry:
223 if (parameters.size()) {
224 errors.error(offset, "shader 'main' must have zero parameters");
225 return false;
226 }
227 break;
228 }
229 return true;
230}
231
232/**
233 * Checks for a previously existing declaration of this function, reporting errors if there is an
234 * incompatible symbol. Returns true and sets outExistingDecl to point to the existing declaration
235 * (or null if none) on success, returns false on error.
236 */
237static bool find_existing_declaration(const Context& context, SymbolTable& symbols, int offset,
Ethan Nicholas962dec42021-06-10 13:06:39 -0400238 skstd::string_view name,
Ethan Nicholas371f6e12021-05-04 14:30:02 -0400239 std::vector<std::unique_ptr<Variable>>& parameters,
240 const Type* returnType, bool isBuiltin,
241 const FunctionDeclaration** outExistingDecl) {
242 ErrorReporter& errors = context.fErrors;
243 const Symbol* entry = symbols[name];
244 *outExistingDecl = nullptr;
245 if (entry) {
246 std::vector<const FunctionDeclaration*> functions;
247 switch (entry->kind()) {
248 case Symbol::Kind::kUnresolvedFunction:
249 functions = entry->as<UnresolvedFunction>().functions();
250 break;
251 case Symbol::Kind::kFunctionDeclaration:
252 functions.push_back(&entry->as<FunctionDeclaration>());
253 break;
254 default:
255 errors.error(offset, "symbol '" + name + "' was already defined");
256 return false;
257 }
258 for (const FunctionDeclaration* other : functions) {
259 SkASSERT(name == other->name());
260 if (parameters.size() != other->parameters().size()) {
261 continue;
262 }
263 bool match = true;
264 for (size_t i = 0; i < parameters.size(); i++) {
265 if (parameters[i]->type() != other->parameters()[i]->type()) {
266 match = false;
267 break;
268 }
269 }
270 if (!match) {
271 continue;
272 }
273 if (*returnType != other->returnType()) {
274 std::vector<const Variable*> paramPtrs;
275 paramPtrs.reserve(parameters.size());
276 for (std::unique_ptr<Variable>& param : parameters) {
277 paramPtrs.push_back(param.get());
278 }
279 FunctionDeclaration invalidDecl(offset,
280 &other->modifiers(),
281 name,
282 std::move(paramPtrs),
283 returnType,
284 isBuiltin);
285 errors.error(offset,
286 "functions '" + invalidDecl.description() + "' and '" +
287 other->description() + "' differ only in return type");
288 return false;
289 }
290 for (size_t i = 0; i < parameters.size(); i++) {
291 if (parameters[i]->modifiers() != other->parameters()[i]->modifiers()) {
292 errors.error(offset,
293 "modifiers on parameter " + to_string((uint64_t)i + 1) +
294 " differ between declaration and definition");
295 return false;
296 }
297 }
298 if (other->definition() && !other->isBuiltin()) {
299 errors.error(offset, "duplicate definition of " + other->description());
300 return false;
301 }
302 *outExistingDecl = other;
303 break;
304 }
305 }
306 return true;
307}
308
John Stilesf96cb712021-05-05 22:17:04 -0400309FunctionDeclaration::FunctionDeclaration(int offset,
310 const Modifiers* modifiers,
Ethan Nicholas962dec42021-06-10 13:06:39 -0400311 skstd::string_view name,
John Stilesf96cb712021-05-05 22:17:04 -0400312 std::vector<const Variable*> parameters,
313 const Type* returnType,
314 bool builtin)
315 : INHERITED(offset, kSymbolKind, name, /*type=*/nullptr)
316 , fDefinition(nullptr)
317 , fModifiers(modifiers)
318 , fParameters(std::move(parameters))
319 , fReturnType(returnType)
320 , fBuiltin(builtin)
321 , fIsMain(name == "main")
Ethan Nicholasd2e09602021-06-10 11:21:59 -0400322 , fIntrinsicKind(builtin ? identify_intrinsic(String(name)) : kNotIntrinsic) {}
John Stilesf96cb712021-05-05 22:17:04 -0400323
Ethan Nicholas371f6e12021-05-04 14:30:02 -0400324const FunctionDeclaration* FunctionDeclaration::Convert(const Context& context,
John Stiles0b822792021-05-04 17:41:53 -0400325 SymbolTable& symbols, int offset, const Modifiers* modifiers,
Ethan Nicholas962dec42021-06-10 13:06:39 -0400326 skstd::string_view name, std::vector<std::unique_ptr<Variable>> parameters,
Ethan Nicholas371f6e12021-05-04 14:30:02 -0400327 const Type* returnType, bool isBuiltin) {
328 bool isMain = (name == "main");
329
330 const FunctionDeclaration* decl = nullptr;
331 if (!check_modifiers(context, offset, *modifiers) ||
332 !check_return_type(context, offset, *returnType, isBuiltin) ||
John Stiles0b822792021-05-04 17:41:53 -0400333 !check_parameters(context, parameters, isMain, isBuiltin) ||
Ethan Nicholas371f6e12021-05-04 14:30:02 -0400334 (isMain && !check_main_signature(context, offset, *returnType, parameters, isBuiltin)) ||
335 !find_existing_declaration(context, symbols, offset, name, parameters, returnType,
336 isBuiltin, &decl)) {
337 return nullptr;
338 }
339 std::vector<const Variable*> finalParameters;
340 finalParameters.reserve(parameters.size());
John Stilesf96cb712021-05-05 22:17:04 -0400341 for (std::unique_ptr<Variable>& param : parameters) {
Ethan Nicholas371f6e12021-05-04 14:30:02 -0400342 finalParameters.push_back(symbols.takeOwnershipOfSymbol(std::move(param)));
343 }
344 if (decl) {
345 return decl;
346 }
347 auto result = std::make_unique<FunctionDeclaration>(offset, modifiers, name,
348 std::move(finalParameters), returnType,
349 isBuiltin);
350 return symbols.add(std::move(result));
351}
352
John Stilesf96cb712021-05-05 22:17:04 -0400353String FunctionDeclaration::mangledName() const {
354 if ((this->isBuiltin() && !this->definition()) || this->isMain()) {
355 // Builtins without a definition (like `sin` or `sqrt`) must use their real names.
Ethan Nicholasd2e09602021-06-10 11:21:59 -0400356 return String(this->name());
John Stilesf96cb712021-05-05 22:17:04 -0400357 }
358 // GLSL forbids two underscores in a row; add an extra character if necessary to avoid this.
Ethan Nicholasd2e09602021-06-10 11:21:59 -0400359 const char* splitter = this->name().ends_with("_") ? "x_" : "_";
John Stilesf96cb712021-05-05 22:17:04 -0400360 // Rename function to `funcname_returntypeparamtypes`.
361 String result = this->name() + splitter + this->returnType().abbreviatedName();
362 for (const Variable* p : this->parameters()) {
363 result += p->type().abbreviatedName();
364 }
365 return result;
366}
367
368String FunctionDeclaration::description() const {
369 String result = this->returnType().displayName() + " " + this->name() + "(";
370 String separator;
371 for (const Variable* p : this->parameters()) {
372 result += separator;
373 separator = ", ";
374 result += p->type().displayName();
375 result += " ";
376 result += p->name();
377 }
378 result += ")";
379 return result;
380}
381
382bool FunctionDeclaration::matches(const FunctionDeclaration& f) const {
383 if (this->name() != f.name()) {
384 return false;
385 }
386 const std::vector<const Variable*>& parameters = this->parameters();
387 const std::vector<const Variable*>& otherParameters = f.parameters();
388 if (parameters.size() != otherParameters.size()) {
389 return false;
390 }
391 for (size_t i = 0; i < parameters.size(); i++) {
392 if (parameters[i]->type() != otherParameters[i]->type()) {
393 return false;
394 }
395 }
396 return true;
397}
398
399bool FunctionDeclaration::determineFinalTypes(const ExpressionArray& arguments,
400 ParamTypes* outParameterTypes,
401 const Type** outReturnType) const {
402 const std::vector<const Variable*>& parameters = this->parameters();
403 SkASSERT(arguments.size() == parameters.size());
404
405 outParameterTypes->reserve_back(arguments.size());
406 int genericIndex = -1;
407 for (size_t i = 0; i < arguments.size(); i++) {
408 // Non-generic parameters are final as-is.
409 const Type& parameterType = parameters[i]->type();
410 if (parameterType.typeKind() != Type::TypeKind::kGeneric) {
411 outParameterTypes->push_back(&parameterType);
412 continue;
413 }
414 // We use the first generic parameter we find to lock in the generic index;
415 // e.g. if we find `float3` here, all `$genType`s will be assumed to be `float3`.
416 const std::vector<const Type*>& types = parameterType.coercibleTypes();
417 if (genericIndex == -1) {
418 for (size_t j = 0; j < types.size(); j++) {
419 if (arguments[i]->type().canCoerceTo(*types[j], /*allowNarrowing=*/true)) {
420 genericIndex = j;
421 break;
422 }
423 }
424 if (genericIndex == -1) {
425 // The passed-in type wasn't a match for ANY of the generic possibilities.
426 // This function isn't a match at all.
427 return false;
428 }
429 }
430 outParameterTypes->push_back(types[genericIndex]);
431 }
432 // Apply the generic index to our return type.
433 const Type& returnType = this->returnType();
434 if (returnType.typeKind() == Type::TypeKind::kGeneric) {
435 if (genericIndex == -1) {
436 // We don't support functions with a generic return type and no other generics.
437 return false;
438 }
439 *outReturnType = returnType.coercibleTypes()[genericIndex];
440 } else {
441 *outReturnType = &returnType;
442 }
443 return true;
444}
445
Ethan Nicholas371f6e12021-05-04 14:30:02 -0400446} // namespace SkSL