blob: 3b4ba3db83853fa66e6c11c8d07e073183d1ee30 [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
72 // Check modifiers on each function parameter.
73 for (auto& param : parameters) {
74 IRGenerator::CheckModifiers(context, param->fOffset, param->modifiers(),
75 Modifiers::kConst_Flag | Modifiers::kIn_Flag |
76 Modifiers::kOut_Flag, /*permittedLayoutFlags=*/0);
77 const Type& type = param->type();
78 // Only the (builtin) declarations of 'sample' are allowed to have shader/colorFilter or FP
79 // parameters. You can pass other opaque types to functions safely; this restriction is
80 // specific to "child" objects.
81 if ((type.isEffectChild() || type.isFragmentProcessor()) && !isBuiltin) {
82 context.fErrors.error(param->fOffset, "parameters of type '" + type.displayName() +
83 "' not allowed");
84 return false;
85 }
86
87 Modifiers m = param->modifiers();
88 ProgramKind kind = context.fConfig->fKind;
89 if (isMain && (kind == ProgramKind::kRuntimeColorFilter ||
90 kind == ProgramKind::kRuntimeShader ||
John Stilesf7f36ae2021-06-08 14:06:22 -040091 kind == ProgramKind::kRuntimeBlend ||
Ethan Nicholas371f6e12021-05-04 14:30:02 -040092 kind == ProgramKind::kFragmentProcessor)) {
93 // We verify that the signature is fully correct later. For now, if this is an .fp or
94 // runtime effect of any flavor, a float2 param is supposed to be the coords, and
95 // a half4/float parameter is supposed to be the input color:
96 if (type == *context.fTypes.fFloat2) {
97 m.fLayout.fBuiltin = SK_MAIN_COORDS_BUILTIN;
John Stilesf7f36ae2021-06-08 14:06:22 -040098 } else if (typeIsValidForColor(type)) {
Ethan Nicholas371f6e12021-05-04 14:30:02 -040099 m.fLayout.fBuiltin = SK_INPUT_COLOR_BUILTIN;
100 }
101 if (m.fLayout.fBuiltin) {
John Stiles0b822792021-05-04 17:41:53 -0400102 param->setModifiers(context.fModifiersPool->add(m));
Ethan Nicholas371f6e12021-05-04 14:30:02 -0400103 }
104 }
105 if (isMain && (kind == ProgramKind::kFragment)) {
106 // For testing purposes, we have .sksl inputs that are treated as both runtime effects
107 // and fragment shaders. To make that work, fragment shaders are allowed to have a
108 // coords parameter. We turn it into sk_FragCoord.
109 if (type == *context.fTypes.fFloat2) {
110 m.fLayout.fBuiltin = SK_FRAGCOORD_BUILTIN;
John Stiles0b822792021-05-04 17:41:53 -0400111 param->setModifiers(context.fModifiersPool->add(m));
Ethan Nicholas371f6e12021-05-04 14:30:02 -0400112 }
113 }
114 }
115 return true;
116}
117
118static bool check_main_signature(const Context& context, int offset, const Type& returnType,
119 std::vector<std::unique_ptr<Variable>>& parameters,
120 bool isBuiltin) {
121 ErrorReporter& errors = context.fErrors;
122 ProgramKind kind = context.fConfig->fKind;
123
124 auto typeIsValidForColor = [&](const Type& type) {
125 return type == *context.fTypes.fHalf4 || type == *context.fTypes.fFloat4;
126 };
127
128 auto paramIsCoords = [&](int idx) {
129 const Variable& p = *parameters[idx];
130 return p.type() == *context.fTypes.fFloat2 &&
131 p.modifiers().fFlags == 0 &&
132 p.modifiers().fLayout.fBuiltin == (kind == ProgramKind::kFragment
133 ? SK_FRAGCOORD_BUILTIN
134 : SK_MAIN_COORDS_BUILTIN);
135 };
136
137 auto paramIsInputColor = [&](int idx) {
138 return typeIsValidForColor(parameters[idx]->type()) &&
139 parameters[idx]->modifiers().fFlags == 0 &&
140 parameters[idx]->modifiers().fLayout.fBuiltin == SK_INPUT_COLOR_BUILTIN;
141 };
142
143 switch (kind) {
144 case ProgramKind::kRuntimeColorFilter: {
145 // (half4|float4) main(half4|float4)
146 if (!typeIsValidForColor(returnType)) {
147 errors.error(offset, "'main' must return: 'vec4', 'float4', or 'half4'");
148 return false;
149 }
150 bool validParams = (parameters.size() == 1 && paramIsInputColor(0));
151 if (!validParams) {
152 errors.error(offset, "'main' parameter must be 'vec4', 'float4', or 'half4'");
153 return false;
154 }
155 break;
156 }
157 case ProgramKind::kRuntimeShader: {
158 // (half4|float4) main(float2) -or- (half4|float4) main(float2, half4|float4)
159 if (!typeIsValidForColor(returnType)) {
160 errors.error(offset, "'main' must return: 'vec4', 'float4', or 'half4'");
161 return false;
162 }
163 bool validParams =
164 (parameters.size() == 1 && paramIsCoords(0)) ||
165 (parameters.size() == 2 && paramIsCoords(0) && paramIsInputColor(1));
166 if (!validParams) {
167 errors.error(offset, "'main' parameters must be (float2, (vec4|float4|half4)?)");
168 return false;
169 }
170 break;
171 }
John Stilesf7f36ae2021-06-08 14:06:22 -0400172 case ProgramKind::kRuntimeBlend: {
173 // (half4|float4) main(half4|float4, half4|float4)
174 if (!typeIsValidForColor(returnType)) {
175 errors.error(offset, "'main' must return: 'vec4', 'float4', or 'half4'");
176 return false;
177 }
178 if (!(parameters.size() == 2 &&
179 paramIsInputColor(0) &&
180 paramIsInputColor(1))) {
181 errors.error(offset, "'main' parameters must be (vec4|float4|half4, "
182 "vec4|float4|half4)");
183 return false;
184 }
185 break;
186 }
Ethan Nicholas371f6e12021-05-04 14:30:02 -0400187 case ProgramKind::kFragmentProcessor: {
188 if (returnType != *context.fTypes.fHalf4) {
189 errors.error(offset, ".fp 'main' must return 'half4'");
190 return false;
191 }
192 bool validParams = (parameters.size() == 0) ||
193 (parameters.size() == 1 && paramIsCoords(0));
194 if (!validParams) {
195 errors.error(offset, ".fp 'main' must be declared main() or main(float2)");
196 return false;
197 }
198 break;
199 }
200 case ProgramKind::kGeneric:
201 // No rules apply here
202 break;
203 case ProgramKind::kFragment: {
204 bool validParams = (parameters.size() == 0) ||
205 (parameters.size() == 1 && paramIsCoords(0));
206 if (!validParams) {
207 errors.error(offset, "shader 'main' must be main() or main(float2)");
208 return false;
209 }
210 break;
211 }
212 case ProgramKind::kVertex:
213 case ProgramKind::kGeometry:
214 if (parameters.size()) {
215 errors.error(offset, "shader 'main' must have zero parameters");
216 return false;
217 }
218 break;
219 }
220 return true;
221}
222
223/**
224 * Checks for a previously existing declaration of this function, reporting errors if there is an
225 * incompatible symbol. Returns true and sets outExistingDecl to point to the existing declaration
226 * (or null if none) on success, returns false on error.
227 */
228static bool find_existing_declaration(const Context& context, SymbolTable& symbols, int offset,
229 StringFragment name,
230 std::vector<std::unique_ptr<Variable>>& parameters,
231 const Type* returnType, bool isBuiltin,
232 const FunctionDeclaration** outExistingDecl) {
233 ErrorReporter& errors = context.fErrors;
234 const Symbol* entry = symbols[name];
235 *outExistingDecl = nullptr;
236 if (entry) {
237 std::vector<const FunctionDeclaration*> functions;
238 switch (entry->kind()) {
239 case Symbol::Kind::kUnresolvedFunction:
240 functions = entry->as<UnresolvedFunction>().functions();
241 break;
242 case Symbol::Kind::kFunctionDeclaration:
243 functions.push_back(&entry->as<FunctionDeclaration>());
244 break;
245 default:
246 errors.error(offset, "symbol '" + name + "' was already defined");
247 return false;
248 }
249 for (const FunctionDeclaration* other : functions) {
250 SkASSERT(name == other->name());
251 if (parameters.size() != other->parameters().size()) {
252 continue;
253 }
254 bool match = true;
255 for (size_t i = 0; i < parameters.size(); i++) {
256 if (parameters[i]->type() != other->parameters()[i]->type()) {
257 match = false;
258 break;
259 }
260 }
261 if (!match) {
262 continue;
263 }
264 if (*returnType != other->returnType()) {
265 std::vector<const Variable*> paramPtrs;
266 paramPtrs.reserve(parameters.size());
267 for (std::unique_ptr<Variable>& param : parameters) {
268 paramPtrs.push_back(param.get());
269 }
270 FunctionDeclaration invalidDecl(offset,
271 &other->modifiers(),
272 name,
273 std::move(paramPtrs),
274 returnType,
275 isBuiltin);
276 errors.error(offset,
277 "functions '" + invalidDecl.description() + "' and '" +
278 other->description() + "' differ only in return type");
279 return false;
280 }
281 for (size_t i = 0; i < parameters.size(); i++) {
282 if (parameters[i]->modifiers() != other->parameters()[i]->modifiers()) {
283 errors.error(offset,
284 "modifiers on parameter " + to_string((uint64_t)i + 1) +
285 " differ between declaration and definition");
286 return false;
287 }
288 }
289 if (other->definition() && !other->isBuiltin()) {
290 errors.error(offset, "duplicate definition of " + other->description());
291 return false;
292 }
293 *outExistingDecl = other;
294 break;
295 }
296 }
297 return true;
298}
299
John Stilesf96cb712021-05-05 22:17:04 -0400300FunctionDeclaration::FunctionDeclaration(int offset,
301 const Modifiers* modifiers,
302 StringFragment name,
303 std::vector<const Variable*> parameters,
304 const Type* returnType,
305 bool builtin)
306 : INHERITED(offset, kSymbolKind, name, /*type=*/nullptr)
307 , fDefinition(nullptr)
308 , fModifiers(modifiers)
309 , fParameters(std::move(parameters))
310 , fReturnType(returnType)
311 , fBuiltin(builtin)
312 , fIsMain(name == "main")
313 , fIntrinsicKind(builtin ? identify_intrinsic(name) : kNotIntrinsic) {}
314
Ethan Nicholas371f6e12021-05-04 14:30:02 -0400315const FunctionDeclaration* FunctionDeclaration::Convert(const Context& context,
John Stiles0b822792021-05-04 17:41:53 -0400316 SymbolTable& symbols, int offset, const Modifiers* modifiers,
Ethan Nicholas371f6e12021-05-04 14:30:02 -0400317 StringFragment name, std::vector<std::unique_ptr<Variable>> parameters,
318 const Type* returnType, bool isBuiltin) {
319 bool isMain = (name == "main");
320
321 const FunctionDeclaration* decl = nullptr;
322 if (!check_modifiers(context, offset, *modifiers) ||
323 !check_return_type(context, offset, *returnType, isBuiltin) ||
John Stiles0b822792021-05-04 17:41:53 -0400324 !check_parameters(context, parameters, isMain, isBuiltin) ||
Ethan Nicholas371f6e12021-05-04 14:30:02 -0400325 (isMain && !check_main_signature(context, offset, *returnType, parameters, isBuiltin)) ||
326 !find_existing_declaration(context, symbols, offset, name, parameters, returnType,
327 isBuiltin, &decl)) {
328 return nullptr;
329 }
330 std::vector<const Variable*> finalParameters;
331 finalParameters.reserve(parameters.size());
John Stilesf96cb712021-05-05 22:17:04 -0400332 for (std::unique_ptr<Variable>& param : parameters) {
Ethan Nicholas371f6e12021-05-04 14:30:02 -0400333 finalParameters.push_back(symbols.takeOwnershipOfSymbol(std::move(param)));
334 }
335 if (decl) {
336 return decl;
337 }
338 auto result = std::make_unique<FunctionDeclaration>(offset, modifiers, name,
339 std::move(finalParameters), returnType,
340 isBuiltin);
341 return symbols.add(std::move(result));
342}
343
John Stilesf96cb712021-05-05 22:17:04 -0400344String FunctionDeclaration::mangledName() const {
345 if ((this->isBuiltin() && !this->definition()) || this->isMain()) {
346 // Builtins without a definition (like `sin` or `sqrt`) must use their real names.
347 return this->name();
348 }
349 // GLSL forbids two underscores in a row; add an extra character if necessary to avoid this.
350 const char* splitter = this->name().endsWith("_") ? "x_" : "_";
351 // Rename function to `funcname_returntypeparamtypes`.
352 String result = this->name() + splitter + this->returnType().abbreviatedName();
353 for (const Variable* p : this->parameters()) {
354 result += p->type().abbreviatedName();
355 }
356 return result;
357}
358
359String FunctionDeclaration::description() const {
360 String result = this->returnType().displayName() + " " + this->name() + "(";
361 String separator;
362 for (const Variable* p : this->parameters()) {
363 result += separator;
364 separator = ", ";
365 result += p->type().displayName();
366 result += " ";
367 result += p->name();
368 }
369 result += ")";
370 return result;
371}
372
373bool FunctionDeclaration::matches(const FunctionDeclaration& f) const {
374 if (this->name() != f.name()) {
375 return false;
376 }
377 const std::vector<const Variable*>& parameters = this->parameters();
378 const std::vector<const Variable*>& otherParameters = f.parameters();
379 if (parameters.size() != otherParameters.size()) {
380 return false;
381 }
382 for (size_t i = 0; i < parameters.size(); i++) {
383 if (parameters[i]->type() != otherParameters[i]->type()) {
384 return false;
385 }
386 }
387 return true;
388}
389
390bool FunctionDeclaration::determineFinalTypes(const ExpressionArray& arguments,
391 ParamTypes* outParameterTypes,
392 const Type** outReturnType) const {
393 const std::vector<const Variable*>& parameters = this->parameters();
394 SkASSERT(arguments.size() == parameters.size());
395
396 outParameterTypes->reserve_back(arguments.size());
397 int genericIndex = -1;
398 for (size_t i = 0; i < arguments.size(); i++) {
399 // Non-generic parameters are final as-is.
400 const Type& parameterType = parameters[i]->type();
401 if (parameterType.typeKind() != Type::TypeKind::kGeneric) {
402 outParameterTypes->push_back(&parameterType);
403 continue;
404 }
405 // We use the first generic parameter we find to lock in the generic index;
406 // e.g. if we find `float3` here, all `$genType`s will be assumed to be `float3`.
407 const std::vector<const Type*>& types = parameterType.coercibleTypes();
408 if (genericIndex == -1) {
409 for (size_t j = 0; j < types.size(); j++) {
410 if (arguments[i]->type().canCoerceTo(*types[j], /*allowNarrowing=*/true)) {
411 genericIndex = j;
412 break;
413 }
414 }
415 if (genericIndex == -1) {
416 // The passed-in type wasn't a match for ANY of the generic possibilities.
417 // This function isn't a match at all.
418 return false;
419 }
420 }
421 outParameterTypes->push_back(types[genericIndex]);
422 }
423 // Apply the generic index to our return type.
424 const Type& returnType = this->returnType();
425 if (returnType.typeKind() == Type::TypeKind::kGeneric) {
426 if (genericIndex == -1) {
427 // We don't support functions with a generic return type and no other generics.
428 return false;
429 }
430 *outReturnType = returnType.coercibleTypes()[genericIndex];
431 } else {
432 *outReturnType = &returnType;
433 }
434 return true;
435}
436
Ethan Nicholas371f6e12021-05-04 14:30:02 -0400437} // namespace SkSL