blob: a92aa580b825d5b1634a72d329fe9838b03b38b0 [file] [log] [blame]
John Stiles8d130842021-08-27 12:42:45 -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/SkSLAnalysis.h"
9#include "src/sksl/SkSLContext.h"
10#include "src/sksl/SkSLProgramSettings.h"
11#include "src/sksl/ir/SkSLFunctionCall.h"
12#include "src/sksl/ir/SkSLFunctionDefinition.h"
13#include "src/sksl/ir/SkSLReturnStatement.h"
14
John Stiles1c5eb4b2021-09-21 14:36:34 -040015#include <forward_list>
16
John Stiles8d130842021-08-27 12:42:45 -040017namespace SkSL {
18
John Stiles3b204892021-08-27 17:35:35 -040019std::unique_ptr<FunctionDefinition> FunctionDefinition::Convert(const Context& context,
Brian Osmancc914522021-09-24 18:58:37 +000020 int offset,
John Stiles3b204892021-08-27 17:35:35 -040021 const FunctionDeclaration& function,
22 std::unique_ptr<Statement> body,
23 bool builtin) {
John Stiles8d130842021-08-27 12:42:45 -040024 class Finalizer : public ProgramWriter {
25 public:
26 Finalizer(const Context& context, const FunctionDeclaration& function,
27 IntrinsicSet* referencedIntrinsics)
28 : fContext(context)
29 , fFunction(function)
30 , fReferencedIntrinsics(referencedIntrinsics) {}
31
32 ~Finalizer() override {
John Stiles1c5eb4b2021-09-21 14:36:34 -040033 SkASSERT(fBreakableLevel == 0);
34 SkASSERT(fContinuableLevel == std::forward_list<int>{0});
John Stiles8d130842021-08-27 12:42:45 -040035 }
36
37 bool functionReturnsValue() const {
38 return !fFunction.returnType().isVoid();
39 }
40
41 bool visitExpression(Expression& expr) override {
42 if (expr.is<FunctionCall>()) {
43 const FunctionDeclaration& func = expr.as<FunctionCall>().function();
44 if (func.isBuiltin() && func.definition()) {
45 fReferencedIntrinsics->insert(&func);
46 }
47 }
48 return INHERITED::visitExpression(expr);
49 }
50
51 bool visitStatement(Statement& stmt) override {
52 switch (stmt.kind()) {
53 case Statement::Kind::kReturn: {
54 // Early returns from a vertex main() function will bypass sk_Position
55 // normalization, so SkASSERT that we aren't doing that. If this becomes an
56 // issue, we can add normalization before each return statement.
57 if (fContext.fConfig->fKind == ProgramKind::kVertex && fFunction.isMain()) {
58 fContext.fErrors->error(
Brian Osmancc914522021-09-24 18:58:37 +000059 stmt.fOffset,
John Stiles8d130842021-08-27 12:42:45 -040060 "early returns from vertex programs are not supported");
61 }
62
63 // Verify that the return statement matches the function's return type.
64 ReturnStatement& returnStmt = stmt.as<ReturnStatement>();
65 if (returnStmt.expression()) {
66 if (this->functionReturnsValue()) {
67 // Coerce return expression to the function's return type.
68 returnStmt.setExpression(fFunction.returnType().coerceExpression(
69 std::move(returnStmt.expression()), fContext));
70 } else {
71 // Returning something from a function with a void return type.
72 returnStmt.setExpression(nullptr);
Brian Osmancc914522021-09-24 18:58:37 +000073 fContext.fErrors->error(returnStmt.fOffset,
John Stiles8d130842021-08-27 12:42:45 -040074 "may not return a value from a void function");
75 }
76 } else {
77 if (this->functionReturnsValue()) {
78 // Returning nothing from a function with a non-void return type.
Brian Osmancc914522021-09-24 18:58:37 +000079 fContext.fErrors->error(returnStmt.fOffset,
John Stiles8d130842021-08-27 12:42:45 -040080 "expected function to return '" +
81 fFunction.returnType().displayName() + "'");
82 }
83 }
84 break;
85 }
86 case Statement::Kind::kDo:
87 case Statement::Kind::kFor: {
88 ++fBreakableLevel;
John Stiles1c5eb4b2021-09-21 14:36:34 -040089 ++fContinuableLevel.front();
John Stiles8d130842021-08-27 12:42:45 -040090 bool result = INHERITED::visitStatement(stmt);
John Stiles1c5eb4b2021-09-21 14:36:34 -040091 --fContinuableLevel.front();
John Stiles8d130842021-08-27 12:42:45 -040092 --fBreakableLevel;
93 return result;
94 }
95 case Statement::Kind::kSwitch: {
96 ++fBreakableLevel;
John Stiles1c5eb4b2021-09-21 14:36:34 -040097 fContinuableLevel.push_front(0);
John Stiles8d130842021-08-27 12:42:45 -040098 bool result = INHERITED::visitStatement(stmt);
John Stiles1c5eb4b2021-09-21 14:36:34 -040099 fContinuableLevel.pop_front();
John Stiles8d130842021-08-27 12:42:45 -0400100 --fBreakableLevel;
101 return result;
102 }
103 case Statement::Kind::kBreak:
John Stiles1c5eb4b2021-09-21 14:36:34 -0400104 if (fBreakableLevel == 0) {
Brian Osmancc914522021-09-24 18:58:37 +0000105 fContext.fErrors->error(stmt.fOffset,
John Stiles8d130842021-08-27 12:42:45 -0400106 "break statement must be inside a loop or switch");
107 }
108 break;
109 case Statement::Kind::kContinue:
John Stiles1c5eb4b2021-09-21 14:36:34 -0400110 if (fContinuableLevel.front() == 0) {
111 if (std::any_of(fContinuableLevel.begin(),
112 fContinuableLevel.end(),
113 [](int level) { return level > 0; })) {
Brian Osmancc914522021-09-24 18:58:37 +0000114 fContext.fErrors->error(stmt.fOffset,
John Stiles1c5eb4b2021-09-21 14:36:34 -0400115 "continue statement cannot be used in a switch");
116 } else {
Brian Osmancc914522021-09-24 18:58:37 +0000117 fContext.fErrors->error(stmt.fOffset,
John Stiles1c5eb4b2021-09-21 14:36:34 -0400118 "continue statement must be inside a loop");
119 }
John Stiles8d130842021-08-27 12:42:45 -0400120 }
121 break;
122 default:
123 break;
124 }
125 return INHERITED::visitStatement(stmt);
126 }
127
128 private:
129 const Context& fContext;
130 const FunctionDeclaration& fFunction;
131 // which intrinsics have we encountered in this function
132 IntrinsicSet* fReferencedIntrinsics;
133 // how deeply nested we are in breakable constructs (for, do, switch).
134 int fBreakableLevel = 0;
135 // how deeply nested we are in continuable constructs (for, do).
John Stiles1c5eb4b2021-09-21 14:36:34 -0400136 // We keep a stack (via a forward_list) in order to disallow continue inside of switch.
137 std::forward_list<int> fContinuableLevel{0};
John Stiles8d130842021-08-27 12:42:45 -0400138
139 using INHERITED = ProgramWriter;
140 };
141
John Stiles3b204892021-08-27 17:35:35 -0400142 IntrinsicSet referencedIntrinsics;
143 Finalizer(context, function, &referencedIntrinsics).visitStatement(*body);
John Stiles8d130842021-08-27 12:42:45 -0400144
145 if (Analysis::CanExitWithoutReturningValue(function, *body)) {
Brian Osmancc914522021-09-24 18:58:37 +0000146 context.fErrors->error(function.fOffset, "function '" + function.name() +
John Stiles8d130842021-08-27 12:42:45 -0400147 "' can exit without returning a value");
148 }
John Stiles3b204892021-08-27 17:35:35 -0400149
Brian Osmancc914522021-09-24 18:58:37 +0000150 return std::make_unique<FunctionDefinition>(offset, &function, builtin, std::move(body),
John Stiles3b204892021-08-27 17:35:35 -0400151 std::move(referencedIntrinsics));
John Stiles8d130842021-08-27 12:42:45 -0400152}
153
154} // namespace SkSL