blob: 80dc60fa58cee310e5fc54436f6e183fb6126afc [file] [log] [blame]
Ethan Nicholas1ff76092021-01-28 10:02:43 -05001/*
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
Ethan Nicholasdaed2592021-03-04 14:30:25 -05008#include "include/sksl/DSLFunction.h"
Ethan Nicholas1ff76092021-01-28 10:02:43 -05009
Ethan Nicholasdaed2592021-03-04 14:30:25 -050010#include "include/sksl/DSLVar.h"
Ethan Nicholas1ff76092021-01-28 10:02:43 -050011#include "src/sksl/SkSLAnalysis.h"
12#include "src/sksl/SkSLCompiler.h"
13#include "src/sksl/SkSLIRGenerator.h"
Ethan Nicholasdaed2592021-03-04 14:30:25 -050014#include "src/sksl/dsl/priv/DSLWriter.h"
Ethan Nicholas57709e12021-08-10 15:02:51 -040015#include "src/sksl/ir/SkSLFunctionPrototype.h"
Ethan Nicholas1ff76092021-01-28 10:02:43 -050016#include "src/sksl/ir/SkSLReturnStatement.h"
17
18namespace SkSL {
19
20namespace dsl {
21
Ethan Nicholas292a09d2021-07-14 09:52:16 -040022void DSLFunction::init(DSLModifiers modifiers, const DSLType& returnType, skstd::string_view name,
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -040023 SkTArray<DSLParameter*> params, PositionInfo pos) {
Ethan Nicholas600481f2021-09-01 09:39:34 -040024 fPosition = pos;
Ethan Nicholas292a09d2021-07-14 09:52:16 -040025 // Conservatively assume all user-defined functions have side effects.
26 if (!DSLWriter::IsModule()) {
27 modifiers.fModifiers.fFlags |= Modifiers::kHasSideEffects_Flag;
28 }
29
Ethan Nicholas459777a2021-07-16 11:16:27 -040030 if (DSLWriter::Settings().fForceNoInline) {
Ethan Nicholas292a09d2021-07-14 09:52:16 -040031 // Apply the `noinline` modifier to every function. This allows us to test Runtime
32 // Effects without any inlining, even when the code is later added to a paint.
33 modifiers.fModifiers.fFlags &= ~Modifiers::kInline_Flag;
34 modifiers.fModifiers.fFlags |= Modifiers::kNoInline_Flag;
35 }
36
Ethan Nicholas371f6e12021-05-04 14:30:02 -040037 std::vector<std::unique_ptr<Variable>> paramVars;
Ethan Nicholasdaed2592021-03-04 14:30:25 -050038 paramVars.reserve(params.size());
Ethan Nicholasa2d22b22021-07-15 10:35:54 -040039 for (DSLParameter* param : params) {
Ethan Nicholas961d9442021-03-16 16:37:29 -040040 if (param->fDeclared) {
Ethan Nicholas4a5e22a2021-08-13 17:29:51 -040041 DSLWriter::ReportError("parameter has already been used in another function");
Ethan Nicholas961d9442021-03-16 16:37:29 -040042 }
Ethan Nicholas51b4b862021-08-31 16:12:40 -040043 SkASSERT(!param->fInitialValue.hasValue());
Ethan Nicholasa2d22b22021-07-15 10:35:54 -040044 SkASSERT(!param->fDeclaration);
Ethan Nicholas961d9442021-03-16 16:37:29 -040045 param->fDeclared = true;
Ethan Nicholasa2d22b22021-07-15 10:35:54 -040046 std::unique_ptr<SkSL::Variable> paramVar = DSLWriter::CreateParameterVar(*param);
Ethan Nicholas6b3c6fc2021-05-04 15:36:06 -040047 if (!paramVar) {
48 return;
49 }
Ethan Nicholas371f6e12021-05-04 14:30:02 -040050 paramVars.push_back(std::move(paramVar));
Ethan Nicholasdaed2592021-03-04 14:30:25 -050051 }
Ethan Nicholas6b3c6fc2021-05-04 15:36:06 -040052 SkASSERT(paramVars.size() == params.size());
Ethan Nicholas371f6e12021-05-04 14:30:02 -040053 fDecl = SkSL::FunctionDeclaration::Convert(DSLWriter::Context(),
54 *DSLWriter::SymbolTable(),
Ethan Nicholas89cfde12021-09-27 11:20:34 -040055 pos.line(),
Ethan Nicholas292a09d2021-07-14 09:52:16 -040056 DSLWriter::Modifiers(modifiers.fModifiers),
Ethan Nicholase0531f52021-07-26 16:07:23 -040057 name == "main" ? name : DSLWriter::Name(name),
Ethan Nicholas722cb672021-05-06 10:47:06 -040058 std::move(paramVars), &returnType.skslType(),
Ethan Nicholas292a09d2021-07-14 09:52:16 -040059 DSLWriter::IsModule());
Ethan Nicholas600481f2021-09-01 09:39:34 -040060 DSLWriter::ReportErrors(pos);
Ethan Nicholas292a09d2021-07-14 09:52:16 -040061 if (fDecl) {
62 for (size_t i = 0; i < params.size(); ++i) {
63 params[i]->fVar = fDecl->parameters()[i];
Ethan Nicholas5c4463e2021-08-29 14:31:19 -040064 params[i]->fInitialized = true;
Ethan Nicholas292a09d2021-07-14 09:52:16 -040065 }
Ethan Nicholas57709e12021-08-10 15:02:51 -040066 // We don't know when this function is going to be defined; go ahead and add a prototype in
67 // case the definition is delayed. If we end up defining the function immediately, we'll
68 // remove the prototype in define().
69 DSLWriter::ProgramElements().push_back(std::make_unique<SkSL::FunctionPrototype>(
Ethan Nicholas89cfde12021-09-27 11:20:34 -040070 pos.line(), fDecl, DSLWriter::IsModule()));
Ethan Nicholas292a09d2021-07-14 09:52:16 -040071 }
Ethan Nicholasdaed2592021-03-04 14:30:25 -050072}
73
Ethan Nicholasc9d65f02021-09-10 11:57:46 -040074void DSLFunction::define(DSLBlock block, PositionInfo pos) {
John Stiles3b204892021-08-27 17:35:35 -040075 std::unique_ptr<SkSL::Block> body = block.release();
Ethan Nicholas371f6e12021-05-04 14:30:02 -040076 if (!fDecl) {
Ethan Nicholas292a09d2021-07-14 09:52:16 -040077 // Evidently we failed to create the declaration; error should already have been reported.
78 // Release the block so we don't fail its destructor assert.
Ethan Nicholas371f6e12021-05-04 14:30:02 -040079 return;
80 }
Ethan Nicholas57709e12021-08-10 15:02:51 -040081 if (!DSLWriter::ProgramElements().empty()) {
82 // If the last ProgramElement was the prototype for this function, it was unnecessary and we
83 // can remove it.
84 const SkSL::ProgramElement& last = *DSLWriter::ProgramElements().back();
85 if (last.is<SkSL::FunctionPrototype>()) {
86 const SkSL::FunctionPrototype& prototype = last.as<SkSL::FunctionPrototype>();
87 if (&prototype.declaration() == fDecl) {
88 DSLWriter::ProgramElements().pop_back();
89 }
90 }
91 }
Ethan Nicholasc9d65f02021-09-10 11:57:46 -040092 if (fDecl->definition()) {
93 DSLWriter::ReportError(String::printf("function '%s' was already defined",
94 fDecl->description().c_str()), pos);
95 block.release();
96 return;
97 }
John Stiles3b204892021-08-27 17:35:35 -040098 // Append sk_Position fixup to the bottom of main() if this is a vertex program.
99 DSLWriter::IRGenerator().appendRTAdjustFixupToVertexMain(*fDecl, body.get());
100 std::unique_ptr<FunctionDefinition> function = FunctionDefinition::Convert(DSLWriter::Context(),
Ethan Nicholas89cfde12021-09-27 11:20:34 -0400101 pos.line(),
John Stiles3b204892021-08-27 17:35:35 -0400102 *fDecl,
103 std::move(body),
104 /*builtin=*/false);
Ethan Nicholas600481f2021-09-01 09:39:34 -0400105 DSLWriter::ReportErrors(fPosition);
Ethan Nicholas051aeb72021-09-24 16:39:19 -0400106 fDecl->setDefinition(function.get());
Ethan Nicholase2c05042021-02-03 10:27:22 -0500107 DSLWriter::ProgramElements().push_back(std::move(function));
Ethan Nicholas1ff76092021-01-28 10:02:43 -0500108}
109
Ethan Nicholas722cb672021-05-06 10:47:06 -0400110DSLExpression DSLFunction::call(SkTArray<DSLWrapper<DSLExpression>> args) {
Ethan Nicholas80f62352021-04-09 12:25:03 -0400111 ExpressionArray released;
112 released.reserve_back(args.size());
Ethan Nicholas722cb672021-05-06 10:47:06 -0400113 for (DSLWrapper<DSLExpression>& arg : args) {
114 released.push_back(arg->release());
Ethan Nicholas80f62352021-04-09 12:25:03 -0400115 }
Ethan Nicholas9a1f92e2021-09-09 15:03:22 -0400116 return this->call(std::move(released));
117}
118
119DSLExpression DSLFunction::call(ExpressionArray args) {
120 std::unique_ptr<SkSL::Expression> result = DSLWriter::Call(*fDecl, std::move(args));
Ethan Nicholas292a09d2021-07-14 09:52:16 -0400121 return result ? DSLExpression(std::move(result)) : DSLExpression();
Ethan Nicholasdaed2592021-03-04 14:30:25 -0500122}
123
Ethan Nicholas1ff76092021-01-28 10:02:43 -0500124} // namespace dsl
125
126} // namespace SkSL