blob: ba59e66feab0b4adad9f51cd13c505892e87feaa [file] [log] [blame]
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001/*
2 * Copyright 2020 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
Brian Osman1298bc42020-06-30 13:39:35 -040010#include "include/private/SkSLSampleUsage.h"
John Stilesdce4d3e2020-09-25 14:35:13 -040011#include "src/sksl/SkSLErrorReporter.h"
Michael Ludwig8f3a8362020-06-29 17:27:00 -040012#include "src/sksl/ir/SkSLExpression.h"
13#include "src/sksl/ir/SkSLProgram.h"
14#include "src/sksl/ir/SkSLProgramElement.h"
15#include "src/sksl/ir/SkSLStatement.h"
16
17// ProgramElements
18#include "src/sksl/ir/SkSLEnum.h"
19#include "src/sksl/ir/SkSLExtension.h"
20#include "src/sksl/ir/SkSLFunctionDefinition.h"
21#include "src/sksl/ir/SkSLInterfaceBlock.h"
22#include "src/sksl/ir/SkSLModifiers.h"
23#include "src/sksl/ir/SkSLSection.h"
24#include "src/sksl/ir/SkSLVarDeclarations.h"
25
26// Statements
27#include "src/sksl/ir/SkSLBlock.h"
28#include "src/sksl/ir/SkSLBreakStatement.h"
29#include "src/sksl/ir/SkSLContinueStatement.h"
30#include "src/sksl/ir/SkSLDiscardStatement.h"
31#include "src/sksl/ir/SkSLDoStatement.h"
32#include "src/sksl/ir/SkSLExpressionStatement.h"
33#include "src/sksl/ir/SkSLForStatement.h"
34#include "src/sksl/ir/SkSLIfStatement.h"
35#include "src/sksl/ir/SkSLNop.h"
36#include "src/sksl/ir/SkSLReturnStatement.h"
37#include "src/sksl/ir/SkSLSwitchStatement.h"
Michael Ludwig8f3a8362020-06-29 17:27:00 -040038#include "src/sksl/ir/SkSLWhileStatement.h"
39
40// Expressions
41#include "src/sksl/ir/SkSLBinaryExpression.h"
42#include "src/sksl/ir/SkSLBoolLiteral.h"
43#include "src/sksl/ir/SkSLConstructor.h"
44#include "src/sksl/ir/SkSLExternalFunctionCall.h"
45#include "src/sksl/ir/SkSLExternalValueReference.h"
46#include "src/sksl/ir/SkSLFieldAccess.h"
47#include "src/sksl/ir/SkSLFloatLiteral.h"
48#include "src/sksl/ir/SkSLFunctionCall.h"
49#include "src/sksl/ir/SkSLFunctionReference.h"
50#include "src/sksl/ir/SkSLIndexExpression.h"
John Stiles98c1f822020-09-09 14:18:53 -040051#include "src/sksl/ir/SkSLInlineMarker.h"
Michael Ludwig8f3a8362020-06-29 17:27:00 -040052#include "src/sksl/ir/SkSLIntLiteral.h"
53#include "src/sksl/ir/SkSLNullLiteral.h"
54#include "src/sksl/ir/SkSLPostfixExpression.h"
55#include "src/sksl/ir/SkSLPrefixExpression.h"
56#include "src/sksl/ir/SkSLSetting.h"
57#include "src/sksl/ir/SkSLSwizzle.h"
58#include "src/sksl/ir/SkSLTernaryExpression.h"
59#include "src/sksl/ir/SkSLTypeReference.h"
60#include "src/sksl/ir/SkSLVariableReference.h"
61
62namespace SkSL {
63
64namespace {
65
66static bool is_sample_call_to_fp(const FunctionCall& fc, const Variable& fp) {
Ethan Nicholas0dec9922020-10-05 15:51:52 -040067 const FunctionDeclaration& f = fc.function();
Ethan Nicholased84b732020-10-08 11:45:44 -040068 return f.isBuiltin() && f.name() == "sample" && fc.arguments().size() >= 1 &&
Ethan Nicholas0dec9922020-10-05 15:51:52 -040069 fc.arguments()[0]->is<VariableReference>() &&
Ethan Nicholas78686922020-10-08 06:46:27 -040070 fc.arguments()[0]->as<VariableReference>().variable() == &fp;
Michael Ludwig8f3a8362020-06-29 17:27:00 -040071}
72
Brian Osman1298bc42020-06-30 13:39:35 -040073// Visitor that determines the merged SampleUsage for a given child 'fp' in the program.
74class MergeSampleUsageVisitor : public ProgramVisitor {
Michael Ludwig8f3a8362020-06-29 17:27:00 -040075public:
John Stiles933abe32020-08-28 11:58:40 -040076 MergeSampleUsageVisitor(const Context& context, const Variable& fp)
77 : fContext(context), fFP(fp) {}
Michael Ludwig8f3a8362020-06-29 17:27:00 -040078
Brian Osman1298bc42020-06-30 13:39:35 -040079 SampleUsage visit(const Program& program) {
80 fUsage = SampleUsage(); // reset to none
John Stilesd7ab4502020-09-24 22:41:00 -040081 INHERITED::visit(program);
Brian Osman1298bc42020-06-30 13:39:35 -040082 return fUsage;
Michael Ludwig8f3a8362020-06-29 17:27:00 -040083 }
84
85protected:
John Stiles933abe32020-08-28 11:58:40 -040086 const Context& fContext;
Michael Ludwig8f3a8362020-06-29 17:27:00 -040087 const Variable& fFP;
Brian Osman1298bc42020-06-30 13:39:35 -040088 SampleUsage fUsage;
Michael Ludwig8f3a8362020-06-29 17:27:00 -040089
90 bool visitExpression(const Expression& e) override {
Brian Osman1298bc42020-06-30 13:39:35 -040091 // Looking for sample(fp, inColor?, ...)
Ethan Nicholase6592142020-09-08 10:22:09 -040092 if (e.kind() == Expression::Kind::kFunctionCall) {
John Stiles403a3632020-08-20 12:11:48 -040093 const FunctionCall& fc = e.as<FunctionCall>();
Brian Osman1298bc42020-06-30 13:39:35 -040094 if (is_sample_call_to_fp(fc, fFP)) {
95 // Determine the type of call at this site, and merge it with the accumulated state
Ethan Nicholas0dec9922020-10-05 15:51:52 -040096 const Expression* lastArg = fc.arguments().back().get();
Brian Osman1298bc42020-06-30 13:39:35 -040097
Ethan Nicholas30d30222020-09-11 12:27:26 -040098 if (lastArg->type() == *fContext.fFloat2_Type) {
Brian Osman1298bc42020-06-30 13:39:35 -040099 fUsage.merge(SampleUsage::Explicit());
Ethan Nicholas30d30222020-09-11 12:27:26 -0400100 } else if (lastArg->type() == *fContext.fFloat3x3_Type) {
Brian Osman1298bc42020-06-30 13:39:35 -0400101 // Determine the type of matrix for this call site
102 if (lastArg->isConstantOrUniform()) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400103 if (lastArg->kind() == Expression::Kind::kVariableReference ||
104 lastArg->kind() == Expression::Kind::kConstructor) {
Brian Osman1298bc42020-06-30 13:39:35 -0400105 // FIXME if this is a constant, we should parse the float3x3 constructor
106 // and determine if the resulting matrix introduces perspective.
107 fUsage.merge(SampleUsage::UniformMatrix(lastArg->description()));
108 } else {
109 // FIXME this is really to workaround a restriction of the downstream
110 // code that relies on the SampleUsage's fExpression to identify uniform
111 // names. Once they are tracked separately, any uniform expression can
112 // work, but right now this avoids issues from '0.5 * matrix' that is
113 // both a constant AND a uniform.
114 fUsage.merge(SampleUsage::VariableMatrix());
115 }
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400116 } else {
Brian Osman1298bc42020-06-30 13:39:35 -0400117 fUsage.merge(SampleUsage::VariableMatrix());
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400118 }
119 } else {
Brian Osman1298bc42020-06-30 13:39:35 -0400120 // The only other signatures do pass-through sampling
121 fUsage.merge(SampleUsage::PassThrough());
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400122 }
Brian Osman1298bc42020-06-30 13:39:35 -0400123 // NOTE: we don't return true here just because we found a sample call. We need to
124 // process the entire program and merge across all encountered calls.
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400125 }
126 }
127
John Stilesd7ab4502020-09-24 22:41:00 -0400128 return INHERITED::visitExpression(e);
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400129 }
130
John Stiles7571f9e2020-09-02 22:42:33 -0400131 using INHERITED = ProgramVisitor;
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400132};
133
Brian Osman92aac1e2020-08-05 16:48:58 -0400134// Visitor that searches through the program for references to a particular builtin variable
135class BuiltinVariableVisitor : public ProgramVisitor {
136public:
137 BuiltinVariableVisitor(int builtin) : fBuiltin(builtin) {}
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400138
139 bool visitExpression(const Expression& e) override {
Brian Osman79457ef2020-09-24 15:01:27 -0400140 if (e.is<VariableReference>()) {
John Stiles403a3632020-08-20 12:11:48 -0400141 const VariableReference& var = e.as<VariableReference>();
Ethan Nicholas78686922020-10-08 06:46:27 -0400142 return var.variable()->modifiers().fLayout.fBuiltin == fBuiltin;
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400143 }
John Stilesd7ab4502020-09-24 22:41:00 -0400144 return INHERITED::visitExpression(e);
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400145 }
146
Brian Osman92aac1e2020-08-05 16:48:58 -0400147 int fBuiltin;
148
John Stiles7571f9e2020-09-02 22:42:33 -0400149 using INHERITED = ProgramVisitor;
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400150};
151
Ethan Nicholas6e0fa402020-08-20 14:08:23 -0400152// Visitor that counts the number of nodes visited
153class NodeCountVisitor : public ProgramVisitor {
154public:
John Stiles2c1e4922020-10-01 09:14:14 -0400155 NodeCountVisitor(int limit) : fLimit(limit) {}
156
Ethan Nicholas6e0fa402020-08-20 14:08:23 -0400157 int visit(const Statement& s) {
Ethan Nicholas6e0fa402020-08-20 14:08:23 -0400158 this->visitStatement(s);
159 return fCount;
160 }
161
162 bool visitExpression(const Expression& e) override {
163 ++fCount;
John Stiles2c1e4922020-10-01 09:14:14 -0400164 return (fCount > fLimit) || INHERITED::visitExpression(e);
Ethan Nicholas6e0fa402020-08-20 14:08:23 -0400165 }
166
167 bool visitProgramElement(const ProgramElement& p) override {
168 ++fCount;
John Stiles2c1e4922020-10-01 09:14:14 -0400169 return (fCount > fLimit) || INHERITED::visitProgramElement(p);
Ethan Nicholas6e0fa402020-08-20 14:08:23 -0400170 }
171
172 bool visitStatement(const Statement& s) override {
173 ++fCount;
John Stiles2c1e4922020-10-01 09:14:14 -0400174 return (fCount > fLimit) || INHERITED::visitStatement(s);
Ethan Nicholas6e0fa402020-08-20 14:08:23 -0400175 }
176
177private:
John Stiles2c1e4922020-10-01 09:14:14 -0400178 int fCount = 0;
179 int fLimit;
Ethan Nicholas6e0fa402020-08-20 14:08:23 -0400180
John Stiles7571f9e2020-09-02 22:42:33 -0400181 using INHERITED = ProgramVisitor;
Ethan Nicholas6e0fa402020-08-20 14:08:23 -0400182};
183
Ethan Nicholas765d2fe2020-08-26 08:29:55 -0400184class VariableWriteVisitor : public ProgramVisitor {
185public:
186 VariableWriteVisitor(const Variable* var)
187 : fVar(var) {}
188
189 bool visit(const Statement& s) {
190 return this->visitStatement(s);
191 }
192
193 bool visitExpression(const Expression& e) override {
Brian Osman79457ef2020-09-24 15:01:27 -0400194 if (e.is<VariableReference>()) {
Ethan Nicholas765d2fe2020-08-26 08:29:55 -0400195 const VariableReference& ref = e.as<VariableReference>();
Ethan Nicholas453f67f2020-10-09 10:43:45 -0400196 if (ref.variable() == fVar &&
197 (ref.refKind() == VariableReference::RefKind::kWrite ||
198 ref.refKind() == VariableReference::RefKind::kReadWrite ||
199 ref.refKind() == VariableReference::RefKind::kPointer)) {
Ethan Nicholas765d2fe2020-08-26 08:29:55 -0400200 return true;
201 }
202 }
John Stilesd7ab4502020-09-24 22:41:00 -0400203 return INHERITED::visitExpression(e);
Ethan Nicholas765d2fe2020-08-26 08:29:55 -0400204 }
205
206private:
207 const Variable* fVar;
208
John Stiles7571f9e2020-09-02 22:42:33 -0400209 using INHERITED = ProgramVisitor;
Ethan Nicholas765d2fe2020-08-26 08:29:55 -0400210};
211
John Stilesa976da72020-09-25 23:06:26 -0400212// If a caller doesn't care about errors, we can use this trivial reporter that just counts up.
213class TrivialErrorReporter : public ErrorReporter {
214public:
215 void error(int offset, String) override { ++fErrorCount; }
216 int errorCount() override { return fErrorCount; }
217
218private:
219 int fErrorCount = 0;
220};
221
John Stilesdce4d3e2020-09-25 14:35:13 -0400222// This isn't actually using ProgramVisitor, because it only considers a subset of the fields for
223// any given expression kind. For instance, when indexing an array (e.g. `x[1]`), we only want to
224// know if the base (`x`) is assignable; the index expression (`1`) doesn't need to be.
225class IsAssignableVisitor {
226public:
John Stilesa976da72020-09-25 23:06:26 -0400227 IsAssignableVisitor(VariableReference** assignableVar, ErrorReporter* errors)
228 : fAssignableVar(assignableVar), fErrors(errors) {
229 if (fAssignableVar) {
230 *fAssignableVar = nullptr;
231 }
232 }
John Stilesdce4d3e2020-09-25 14:35:13 -0400233
234 bool visit(Expression& expr) {
235 this->visitExpression(expr);
John Stilesa976da72020-09-25 23:06:26 -0400236 return fErrors->errorCount() == 0;
John Stilesdce4d3e2020-09-25 14:35:13 -0400237 }
238
239 void visitExpression(Expression& expr) {
240 switch (expr.kind()) {
241 case Expression::Kind::kVariableReference: {
242 VariableReference& varRef = expr.as<VariableReference>();
Ethan Nicholas78686922020-10-08 06:46:27 -0400243 const Variable* var = varRef.variable();
Ethan Nicholas041fd0a2020-10-07 16:42:04 -0400244 if (var->modifiers().fFlags & (Modifiers::kConst_Flag | Modifiers::kUniform_Flag |
245 Modifiers::kVarying_Flag)) {
John Stilesa976da72020-09-25 23:06:26 -0400246 fErrors->error(expr.fOffset,
Ethan Nicholase2c49992020-10-05 11:49:11 -0400247 "cannot modify immutable variable '" + var->name() + "'");
John Stilesa976da72020-09-25 23:06:26 -0400248 } else if (fAssignableVar) {
249 SkASSERT(*fAssignableVar == nullptr);
250 *fAssignableVar = &varRef;
John Stilesdce4d3e2020-09-25 14:35:13 -0400251 }
252 break;
253 }
254 case Expression::Kind::kFieldAccess:
Ethan Nicholas7a95b202020-10-09 11:55:40 -0400255 this->visitExpression(*expr.as<FieldAccess>().base());
John Stilesdce4d3e2020-09-25 14:35:13 -0400256 break;
257
258 case Expression::Kind::kSwizzle: {
259 const Swizzle& swizzle = expr.as<Swizzle>();
260 this->checkSwizzleWrite(swizzle);
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400261 this->visitExpression(*swizzle.base());
John Stilesdce4d3e2020-09-25 14:35:13 -0400262 break;
263 }
264 case Expression::Kind::kIndex:
Ethan Nicholas2a4952d2020-10-08 15:35:56 -0400265 this->visitExpression(*expr.as<IndexExpression>().base());
John Stilesdce4d3e2020-09-25 14:35:13 -0400266 break;
267
John Stilesdce4d3e2020-09-25 14:35:13 -0400268 case Expression::Kind::kExternalValue: {
Ethan Nicholas444ccc62020-10-09 10:16:22 -0400269 const ExternalValue& var = expr.as<ExternalValueReference>().value();
270 if (!var.canWrite()) {
John Stilesa976da72020-09-25 23:06:26 -0400271 fErrors->error(expr.fOffset,
Ethan Nicholas444ccc62020-10-09 10:16:22 -0400272 "cannot modify immutable external value '" + var.name() + "'");
John Stilesdce4d3e2020-09-25 14:35:13 -0400273 }
274 break;
275 }
276 default:
John Stilesa976da72020-09-25 23:06:26 -0400277 fErrors->error(expr.fOffset, "cannot assign to this expression");
John Stilesdce4d3e2020-09-25 14:35:13 -0400278 break;
279 }
280 }
281
282private:
283 void checkSwizzleWrite(const Swizzle& swizzle) {
284 int bits = 0;
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400285 for (int idx : swizzle.components()) {
John Stilesdce4d3e2020-09-25 14:35:13 -0400286 SkASSERT(idx <= 3);
287 int bit = 1 << idx;
288 if (bits & bit) {
John Stilesa976da72020-09-25 23:06:26 -0400289 fErrors->error(swizzle.fOffset,
290 "cannot write to the same swizzle field more than once");
John Stilesdce4d3e2020-09-25 14:35:13 -0400291 break;
292 }
293 bits |= bit;
294 }
295 }
296
John Stilesa976da72020-09-25 23:06:26 -0400297 VariableReference** fAssignableVar;
298 ErrorReporter* fErrors;
John Stilesdce4d3e2020-09-25 14:35:13 -0400299
300 using INHERITED = ProgramVisitor;
301};
302
John Stilesa6841be2020-08-06 14:11:56 -0400303} // namespace
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400304
305////////////////////////////////////////////////////////////////////////////////
306// Analysis
307
Brian Osman1298bc42020-06-30 13:39:35 -0400308SampleUsage Analysis::GetSampleUsage(const Program& program, const Variable& fp) {
John Stiles933abe32020-08-28 11:58:40 -0400309 MergeSampleUsageVisitor visitor(*program.fContext, fp);
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400310 return visitor.visit(program);
311}
312
Brian Osman92aac1e2020-08-05 16:48:58 -0400313bool Analysis::ReferencesBuiltin(const Program& program, int builtin) {
314 BuiltinVariableVisitor visitor(builtin);
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400315 return visitor.visit(program);
316}
317
Brian Osman92aac1e2020-08-05 16:48:58 -0400318bool Analysis::ReferencesSampleCoords(const Program& program) {
319 return Analysis::ReferencesBuiltin(program, SK_MAIN_COORDS_BUILTIN);
320}
321
322bool Analysis::ReferencesFragCoords(const Program& program) {
323 return Analysis::ReferencesBuiltin(program, SK_FRAGCOORD_BUILTIN);
324}
325
John Stiles2c1e4922020-10-01 09:14:14 -0400326bool Analysis::NodeCountExceeds(const FunctionDefinition& function, int limit) {
327 return NodeCountVisitor{limit}.visit(*function.fBody) > limit;
Ethan Nicholas6e0fa402020-08-20 14:08:23 -0400328}
329
Ethan Nicholas765d2fe2020-08-26 08:29:55 -0400330bool Analysis::StatementWritesToVariable(const Statement& stmt, const Variable& var) {
331 return VariableWriteVisitor(&var).visit(stmt);
332}
333
John Stilesa976da72020-09-25 23:06:26 -0400334bool Analysis::IsAssignable(Expression& expr, VariableReference** assignableVar,
335 ErrorReporter* errors) {
336 TrivialErrorReporter trivialErrors;
337 return IsAssignableVisitor{assignableVar, errors ? errors : &trivialErrors}.visit(expr);
John Stilesdce4d3e2020-09-25 14:35:13 -0400338}
339
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400340////////////////////////////////////////////////////////////////////////////////
341// ProgramVisitor
342
John Stiles70b82422020-09-30 10:55:12 -0400343template <typename PROG, typename EXPR, typename STMT, typename ELEM>
344bool TProgramVisitor<PROG, EXPR, STMT, ELEM>::visit(PROG program) {
Brian Osman1179fcf2020-10-08 16:04:40 -0400345 for (const auto& pe : program.elements()) {
346 if (this->visitProgramElement(*pe)) {
John Stiles933abe32020-08-28 11:58:40 -0400347 return true;
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400348 }
349 }
John Stiles933abe32020-08-28 11:58:40 -0400350 return false;
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400351}
352
John Stiles70b82422020-09-30 10:55:12 -0400353template <typename PROG, typename EXPR, typename STMT, typename ELEM>
354bool TProgramVisitor<PROG, EXPR, STMT, ELEM>::visitExpression(EXPR e) {
355 switch (e.kind()) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400356 case Expression::Kind::kBoolLiteral:
357 case Expression::Kind::kDefined:
358 case Expression::Kind::kExternalValue:
Ethan Nicholase6592142020-09-08 10:22:09 -0400359 case Expression::Kind::kFloatLiteral:
360 case Expression::Kind::kFunctionReference:
361 case Expression::Kind::kIntLiteral:
362 case Expression::Kind::kNullLiteral:
363 case Expression::Kind::kSetting:
364 case Expression::Kind::kTypeReference:
365 case Expression::Kind::kVariableReference:
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400366 // Leaf expressions return false
367 return false;
John Stiles70b82422020-09-30 10:55:12 -0400368
Ethan Nicholase6592142020-09-08 10:22:09 -0400369 case Expression::Kind::kBinary: {
John Stiles70b82422020-09-30 10:55:12 -0400370 auto& b = e.template as<BinaryExpression>();
371 return this->visitExpression(b.left()) || this->visitExpression(b.right());
372 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400373 case Expression::Kind::kConstructor: {
John Stiles70b82422020-09-30 10:55:12 -0400374 auto& c = e.template as<Constructor>();
375 for (auto& arg : c.arguments()) {
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400376 if (this->visitExpression(*arg)) { return true; }
377 }
John Stiles70b82422020-09-30 10:55:12 -0400378 return false;
379 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400380 case Expression::Kind::kExternalFunctionCall: {
John Stiles70b82422020-09-30 10:55:12 -0400381 auto& c = e.template as<ExternalFunctionCall>();
Ethan Nicholas6e86ec92020-09-30 14:29:56 -0400382 for (auto& arg : c.arguments()) {
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400383 if (this->visitExpression(*arg)) { return true; }
384 }
John Stiles70b82422020-09-30 10:55:12 -0400385 return false;
386 }
John Stilesd7ab4502020-09-24 22:41:00 -0400387 case Expression::Kind::kFieldAccess:
Ethan Nicholas7a95b202020-10-09 11:55:40 -0400388 return this->visitExpression(*e.template as<FieldAccess>().base());
John Stiles70b82422020-09-30 10:55:12 -0400389
Ethan Nicholase6592142020-09-08 10:22:09 -0400390 case Expression::Kind::kFunctionCall: {
John Stiles70b82422020-09-30 10:55:12 -0400391 auto& c = e.template as<FunctionCall>();
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400392 for (auto& arg : c.arguments()) {
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400393 if (this->visitExpression(*arg)) { return true; }
394 }
John Stiles70b82422020-09-30 10:55:12 -0400395 return false;
396 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400397 case Expression::Kind::kIndex: {
John Stiles70b82422020-09-30 10:55:12 -0400398 auto& i = e.template as<IndexExpression>();
Ethan Nicholas2a4952d2020-10-08 15:35:56 -0400399 return this->visitExpression(*i.base()) || this->visitExpression(*i.index());
John Stiles70b82422020-09-30 10:55:12 -0400400 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400401 case Expression::Kind::kPostfix:
Ethan Nicholas444ccc62020-10-09 10:16:22 -0400402 return this->visitExpression(*e.template as<PostfixExpression>().operand());
John Stiles70b82422020-09-30 10:55:12 -0400403
Ethan Nicholase6592142020-09-08 10:22:09 -0400404 case Expression::Kind::kPrefix:
Ethan Nicholas444ccc62020-10-09 10:16:22 -0400405 return this->visitExpression(*e.template as<PrefixExpression>().operand());
John Stiles70b82422020-09-30 10:55:12 -0400406
Ethan Nicholase6592142020-09-08 10:22:09 -0400407 case Expression::Kind::kSwizzle:
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400408 return this->visitExpression(*e.template as<Swizzle>().base());
John Stiles70b82422020-09-30 10:55:12 -0400409
Ethan Nicholase6592142020-09-08 10:22:09 -0400410 case Expression::Kind::kTernary: {
John Stiles70b82422020-09-30 10:55:12 -0400411 auto& t = e.template as<TernaryExpression>();
Ethan Nicholasdd218162020-10-08 05:48:01 -0400412 return this->visitExpression(*t.test()) || this->visitExpression(*t.ifTrue()) ||
413 this->visitExpression(*t.ifFalse());
John Stiles70b82422020-09-30 10:55:12 -0400414 }
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400415 default:
416 SkUNREACHABLE;
417 }
418}
419
John Stiles70b82422020-09-30 10:55:12 -0400420template <typename PROG, typename EXPR, typename STMT, typename ELEM>
421bool TProgramVisitor<PROG, EXPR, STMT, ELEM>::visitStatement(STMT s) {
422 switch (s.kind()) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400423 case Statement::Kind::kBreak:
424 case Statement::Kind::kContinue:
425 case Statement::Kind::kDiscard:
John Stiles98c1f822020-09-09 14:18:53 -0400426 case Statement::Kind::kInlineMarker:
Ethan Nicholase6592142020-09-08 10:22:09 -0400427 case Statement::Kind::kNop:
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400428 // Leaf statements just return false
429 return false;
John Stiles70b82422020-09-30 10:55:12 -0400430
Ethan Nicholase6592142020-09-08 10:22:09 -0400431 case Statement::Kind::kBlock:
John Stiles70b82422020-09-30 10:55:12 -0400432 for (auto& stmt : s.template as<Block>().children()) {
Ethan Nicholas7bd60432020-09-25 14:31:59 -0400433 if (this->visitStatement(*stmt)) {
434 return true;
435 }
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400436 }
437 return false;
John Stiles70b82422020-09-30 10:55:12 -0400438
Ethan Nicholase6592142020-09-08 10:22:09 -0400439 case Statement::Kind::kDo: {
John Stiles70b82422020-09-30 10:55:12 -0400440 auto& d = s.template as<DoStatement>();
441 return this->visitExpression(*d.test()) || this->visitStatement(*d.statement());
442 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400443 case Statement::Kind::kExpression:
John Stiles70b82422020-09-30 10:55:12 -0400444 return this->visitExpression(*s.template as<ExpressionStatement>().expression());
445
Ethan Nicholase6592142020-09-08 10:22:09 -0400446 case Statement::Kind::kFor: {
John Stiles70b82422020-09-30 10:55:12 -0400447 auto& f = s.template as<ForStatement>();
Ethan Nicholas0d31ed52020-10-05 14:47:09 -0400448 return (f.initializer() && this->visitStatement(*f.initializer())) ||
449 (f.test() && this->visitExpression(*f.test())) ||
450 (f.next() && this->visitExpression(*f.next())) ||
451 this->visitStatement(*f.statement());
John Stiles70b82422020-09-30 10:55:12 -0400452 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400453 case Statement::Kind::kIf: {
John Stiles70b82422020-09-30 10:55:12 -0400454 auto& i = s.template as<IfStatement>();
Ethan Nicholas8c44eca2020-10-07 16:47:09 -0400455 return this->visitExpression(*i.test()) ||
456 this->visitStatement(*i.ifTrue()) ||
457 (i.ifFalse() && this->visitStatement(*i.ifFalse()));
John Stiles70b82422020-09-30 10:55:12 -0400458 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400459 case Statement::Kind::kReturn: {
John Stiles70b82422020-09-30 10:55:12 -0400460 auto& r = s.template as<ReturnStatement>();
Ethan Nicholas2a4952d2020-10-08 15:35:56 -0400461 return r.expression() && this->visitExpression(*r.expression());
John Stiles70b82422020-09-30 10:55:12 -0400462 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400463 case Statement::Kind::kSwitch: {
John Stiles70b82422020-09-30 10:55:12 -0400464 auto& sw = s.template as<SwitchStatement>();
465 if (this->visitExpression(*sw.fValue)) {
466 return true;
467 }
468 for (auto& c : sw.fCases) {
469 if (c->fValue && this->visitExpression(*c->fValue)) {
470 return true;
471 }
472 for (auto& st : c->fStatements) {
473 if (this->visitStatement(*st)) {
474 return true;
475 }
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400476 }
477 }
John Stiles70b82422020-09-30 10:55:12 -0400478 return false;
479 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400480 case Statement::Kind::kVarDeclaration: {
John Stiles70b82422020-09-30 10:55:12 -0400481 auto& v = s.template as<VarDeclaration>();
482 for (auto& sizeExpr : v.fSizes) {
483 if (sizeExpr && this->visitExpression(*sizeExpr)) {
484 return true;
485 }
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400486 }
John Stiles70b82422020-09-30 10:55:12 -0400487 return v.fValue && this->visitExpression(*v.fValue);
488 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400489 case Statement::Kind::kWhile: {
John Stiles70b82422020-09-30 10:55:12 -0400490 auto& w = s.template as<WhileStatement>();
Ethan Nicholas2a4952d2020-10-08 15:35:56 -0400491 return this->visitExpression(*w.test()) || this->visitStatement(*w.statement());
John Stiles70b82422020-09-30 10:55:12 -0400492 }
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400493 default:
494 SkUNREACHABLE;
495 }
496}
497
John Stiles70b82422020-09-30 10:55:12 -0400498template <typename PROG, typename EXPR, typename STMT, typename ELEM>
499bool TProgramVisitor<PROG, EXPR, STMT, ELEM>::visitProgramElement(ELEM pe) {
500 switch (pe.kind()) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400501 case ProgramElement::Kind::kEnum:
502 case ProgramElement::Kind::kExtension:
503 case ProgramElement::Kind::kModifiers:
504 case ProgramElement::Kind::kSection:
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400505 // Leaf program elements just return false by default
506 return false;
John Stiles70b82422020-09-30 10:55:12 -0400507
Ethan Nicholase6592142020-09-08 10:22:09 -0400508 case ProgramElement::Kind::kFunction:
John Stiles70b82422020-09-30 10:55:12 -0400509 return this->visitStatement(*pe.template as<FunctionDefinition>().fBody);
510
Ethan Nicholase6592142020-09-08 10:22:09 -0400511 case ProgramElement::Kind::kInterfaceBlock:
John Stiles70b82422020-09-30 10:55:12 -0400512 for (auto& e : pe.template as<InterfaceBlock>().fSizes) {
Ethan Nicholas825268f2020-10-02 16:26:00 -0400513 if (e && this->visitExpression(*e)) {
John Stiles70b82422020-09-30 10:55:12 -0400514 return true;
515 }
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400516 }
517 return false;
John Stiles70b82422020-09-30 10:55:12 -0400518
Brian Osmanc0213602020-10-06 14:43:32 -0400519 case ProgramElement::Kind::kGlobalVar:
520 if (this->visitStatement(*pe.template as<GlobalVarDeclaration>().fDecl)) {
521 return true;
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400522 }
523 return false;
John Stiles70b82422020-09-30 10:55:12 -0400524
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400525 default:
526 SkUNREACHABLE;
527 }
528}
529
John Stiles70b82422020-09-30 10:55:12 -0400530template class TProgramVisitor<const Program&, const Expression&,
531 const Statement&, const ProgramElement&>;
532template class TProgramVisitor<Program&, Expression&, Statement&, ProgramElement&>;
533
John Stilesa6841be2020-08-06 14:11:56 -0400534} // namespace SkSL