blob: 27e00ec2055a361774410c8c972f84cdba6c2f68 [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"
Brian Osman00185012021-02-04 16:07:11 -050011#include "src/sksl/SkSLCompiler.h"
John Stilesdce4d3e2020-09-25 14:35:13 -040012#include "src/sksl/SkSLErrorReporter.h"
Michael Ludwig8f3a8362020-06-29 17:27:00 -040013#include "src/sksl/ir/SkSLExpression.h"
14#include "src/sksl/ir/SkSLProgram.h"
15#include "src/sksl/ir/SkSLProgramElement.h"
16#include "src/sksl/ir/SkSLStatement.h"
17
18// ProgramElements
19#include "src/sksl/ir/SkSLEnum.h"
20#include "src/sksl/ir/SkSLExtension.h"
21#include "src/sksl/ir/SkSLFunctionDefinition.h"
22#include "src/sksl/ir/SkSLInterfaceBlock.h"
23#include "src/sksl/ir/SkSLModifiers.h"
24#include "src/sksl/ir/SkSLSection.h"
25#include "src/sksl/ir/SkSLVarDeclarations.h"
26
27// Statements
28#include "src/sksl/ir/SkSLBlock.h"
29#include "src/sksl/ir/SkSLBreakStatement.h"
30#include "src/sksl/ir/SkSLContinueStatement.h"
31#include "src/sksl/ir/SkSLDiscardStatement.h"
32#include "src/sksl/ir/SkSLDoStatement.h"
33#include "src/sksl/ir/SkSLExpressionStatement.h"
34#include "src/sksl/ir/SkSLForStatement.h"
35#include "src/sksl/ir/SkSLIfStatement.h"
36#include "src/sksl/ir/SkSLNop.h"
37#include "src/sksl/ir/SkSLReturnStatement.h"
38#include "src/sksl/ir/SkSLSwitchStatement.h"
Michael Ludwig8f3a8362020-06-29 17:27:00 -040039
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"
Brian Osmanbe0b3b72021-01-06 14:27:35 -050045#include "src/sksl/ir/SkSLExternalFunctionReference.h"
Michael Ludwig8f3a8362020-06-29 17:27:00 -040046#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"
Michael Ludwig8f3a8362020-06-29 17:27:00 -040053#include "src/sksl/ir/SkSLPostfixExpression.h"
54#include "src/sksl/ir/SkSLPrefixExpression.h"
55#include "src/sksl/ir/SkSLSetting.h"
56#include "src/sksl/ir/SkSLSwizzle.h"
57#include "src/sksl/ir/SkSLTernaryExpression.h"
58#include "src/sksl/ir/SkSLTypeReference.h"
59#include "src/sksl/ir/SkSLVariableReference.h"
60
61namespace SkSL {
62
63namespace {
64
65static bool is_sample_call_to_fp(const FunctionCall& fc, const Variable& fp) {
Ethan Nicholas0dec9922020-10-05 15:51:52 -040066 const FunctionDeclaration& f = fc.function();
Ethan Nicholased84b732020-10-08 11:45:44 -040067 return f.isBuiltin() && f.name() == "sample" && fc.arguments().size() >= 1 &&
Ethan Nicholas0dec9922020-10-05 15:51:52 -040068 fc.arguments()[0]->is<VariableReference>() &&
Ethan Nicholas78686922020-10-08 06:46:27 -040069 fc.arguments()[0]->as<VariableReference>().variable() == &fp;
Michael Ludwig8f3a8362020-06-29 17:27:00 -040070}
71
Brian Osman1298bc42020-06-30 13:39:35 -040072// Visitor that determines the merged SampleUsage for a given child 'fp' in the program.
73class MergeSampleUsageVisitor : public ProgramVisitor {
Michael Ludwig8f3a8362020-06-29 17:27:00 -040074public:
John Stiles933abe32020-08-28 11:58:40 -040075 MergeSampleUsageVisitor(const Context& context, const Variable& fp)
76 : fContext(context), fFP(fp) {}
Michael Ludwig8f3a8362020-06-29 17:27:00 -040077
Brian Osman1298bc42020-06-30 13:39:35 -040078 SampleUsage visit(const Program& program) {
79 fUsage = SampleUsage(); // reset to none
John Stilesd7ab4502020-09-24 22:41:00 -040080 INHERITED::visit(program);
Brian Osman1298bc42020-06-30 13:39:35 -040081 return fUsage;
Michael Ludwig8f3a8362020-06-29 17:27:00 -040082 }
83
84protected:
John Stiles933abe32020-08-28 11:58:40 -040085 const Context& fContext;
Michael Ludwig8f3a8362020-06-29 17:27:00 -040086 const Variable& fFP;
Brian Osman1298bc42020-06-30 13:39:35 -040087 SampleUsage fUsage;
Michael Ludwig8f3a8362020-06-29 17:27:00 -040088
89 bool visitExpression(const Expression& e) override {
Brian Osman1298bc42020-06-30 13:39:35 -040090 // Looking for sample(fp, inColor?, ...)
Ethan Nicholase6592142020-09-08 10:22:09 -040091 if (e.kind() == Expression::Kind::kFunctionCall) {
John Stiles403a3632020-08-20 12:11:48 -040092 const FunctionCall& fc = e.as<FunctionCall>();
Brian Osman1298bc42020-06-30 13:39:35 -040093 if (is_sample_call_to_fp(fc, fFP)) {
94 // Determine the type of call at this site, and merge it with the accumulated state
Ethan Nicholas0dec9922020-10-05 15:51:52 -040095 const Expression* lastArg = fc.arguments().back().get();
Brian Osman1298bc42020-06-30 13:39:35 -040096
John Stiles54e7c052021-01-11 14:22:36 -050097 if (lastArg->type() == *fContext.fTypes.fFloat2) {
Brian Osman1298bc42020-06-30 13:39:35 -040098 fUsage.merge(SampleUsage::Explicit());
John Stiles54e7c052021-01-11 14:22:36 -050099 } else if (lastArg->type() == *fContext.fTypes.fFloat3x3) {
Brian Osman1298bc42020-06-30 13:39:35 -0400100 // Determine the type of matrix for this call site
101 if (lastArg->isConstantOrUniform()) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400102 if (lastArg->kind() == Expression::Kind::kVariableReference ||
103 lastArg->kind() == Expression::Kind::kConstructor) {
Brian Osman1298bc42020-06-30 13:39:35 -0400104 // FIXME if this is a constant, we should parse the float3x3 constructor
105 // and determine if the resulting matrix introduces perspective.
106 fUsage.merge(SampleUsage::UniformMatrix(lastArg->description()));
107 } else {
108 // FIXME this is really to workaround a restriction of the downstream
109 // code that relies on the SampleUsage's fExpression to identify uniform
110 // names. Once they are tracked separately, any uniform expression can
111 // work, but right now this avoids issues from '0.5 * matrix' that is
112 // both a constant AND a uniform.
113 fUsage.merge(SampleUsage::VariableMatrix());
114 }
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400115 } else {
Brian Osman1298bc42020-06-30 13:39:35 -0400116 fUsage.merge(SampleUsage::VariableMatrix());
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400117 }
118 } else {
Brian Osman1298bc42020-06-30 13:39:35 -0400119 // The only other signatures do pass-through sampling
120 fUsage.merge(SampleUsage::PassThrough());
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400121 }
Brian Osman1298bc42020-06-30 13:39:35 -0400122 // NOTE: we don't return true here just because we found a sample call. We need to
123 // process the entire program and merge across all encountered calls.
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400124 }
125 }
126
John Stilesd7ab4502020-09-24 22:41:00 -0400127 return INHERITED::visitExpression(e);
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400128 }
129
John Stiles7571f9e2020-09-02 22:42:33 -0400130 using INHERITED = ProgramVisitor;
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400131};
132
Brian Osman92aac1e2020-08-05 16:48:58 -0400133// Visitor that searches through the program for references to a particular builtin variable
134class BuiltinVariableVisitor : public ProgramVisitor {
135public:
136 BuiltinVariableVisitor(int builtin) : fBuiltin(builtin) {}
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400137
138 bool visitExpression(const Expression& e) override {
Brian Osman79457ef2020-09-24 15:01:27 -0400139 if (e.is<VariableReference>()) {
John Stiles403a3632020-08-20 12:11:48 -0400140 const VariableReference& var = e.as<VariableReference>();
Ethan Nicholas78686922020-10-08 06:46:27 -0400141 return var.variable()->modifiers().fLayout.fBuiltin == fBuiltin;
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400142 }
John Stilesd7ab4502020-09-24 22:41:00 -0400143 return INHERITED::visitExpression(e);
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400144 }
145
Brian Osman92aac1e2020-08-05 16:48:58 -0400146 int fBuiltin;
147
John Stiles7571f9e2020-09-02 22:42:33 -0400148 using INHERITED = ProgramVisitor;
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400149};
150
Ethan Nicholas6e0fa402020-08-20 14:08:23 -0400151// Visitor that counts the number of nodes visited
152class NodeCountVisitor : public ProgramVisitor {
153public:
John Stiles2c1e4922020-10-01 09:14:14 -0400154 NodeCountVisitor(int limit) : fLimit(limit) {}
155
Ethan Nicholas6e0fa402020-08-20 14:08:23 -0400156 int visit(const Statement& s) {
Ethan Nicholas6e0fa402020-08-20 14:08:23 -0400157 this->visitStatement(s);
158 return fCount;
159 }
160
161 bool visitExpression(const Expression& e) override {
162 ++fCount;
John Stiles9b9415e2020-11-23 14:48:06 -0500163 return (fCount >= fLimit) || INHERITED::visitExpression(e);
Ethan Nicholas6e0fa402020-08-20 14:08:23 -0400164 }
165
166 bool visitProgramElement(const ProgramElement& p) override {
167 ++fCount;
John Stiles9b9415e2020-11-23 14:48:06 -0500168 return (fCount >= fLimit) || INHERITED::visitProgramElement(p);
Ethan Nicholas6e0fa402020-08-20 14:08:23 -0400169 }
170
171 bool visitStatement(const Statement& s) override {
172 ++fCount;
John Stiles9b9415e2020-11-23 14:48:06 -0500173 return (fCount >= fLimit) || INHERITED::visitStatement(s);
Ethan Nicholas6e0fa402020-08-20 14:08:23 -0400174 }
175
176private:
John Stiles2c1e4922020-10-01 09:14:14 -0400177 int fCount = 0;
178 int fLimit;
Ethan Nicholas6e0fa402020-08-20 14:08:23 -0400179
John Stiles7571f9e2020-09-02 22:42:33 -0400180 using INHERITED = ProgramVisitor;
Ethan Nicholas6e0fa402020-08-20 14:08:23 -0400181};
182
Brian Osman010ce6a2020-10-19 16:34:10 -0400183class ProgramUsageVisitor : public ProgramVisitor {
Brian Osman2e25ff42020-10-15 10:32:04 -0400184public:
Brian Osman010ce6a2020-10-19 16:34:10 -0400185 ProgramUsageVisitor(ProgramUsage* usage, int delta) : fUsage(usage), fDelta(delta) {}
186
Brian Osman2e25ff42020-10-15 10:32:04 -0400187 bool visitExpression(const Expression& e) override {
188 if (e.is<FunctionCall>()) {
189 const FunctionDeclaration* f = &e.as<FunctionCall>().function();
Brian Osman010ce6a2020-10-19 16:34:10 -0400190 fUsage->fCallCounts[f] += fDelta;
191 SkASSERT(fUsage->fCallCounts[f] >= 0);
192 } else if (e.is<VariableReference>()) {
193 const VariableReference& ref = e.as<VariableReference>();
194 ProgramUsage::VariableCounts& counts = fUsage->fVariableCounts[ref.variable()];
195 switch (ref.refKind()) {
196 case VariableRefKind::kRead:
197 counts.fRead += fDelta;
198 break;
199 case VariableRefKind::kWrite:
200 counts.fWrite += fDelta;
201 break;
202 case VariableRefKind::kReadWrite:
203 case VariableRefKind::kPointer:
204 counts.fRead += fDelta;
205 counts.fWrite += fDelta;
206 break;
207 }
208 SkASSERT(counts.fRead >= 0 && counts.fWrite >= 0);
Brian Osman2e25ff42020-10-15 10:32:04 -0400209 }
210 return INHERITED::visitExpression(e);
211 }
212
Brian Osman010ce6a2020-10-19 16:34:10 -0400213 using ProgramVisitor::visitProgramElement;
214 using ProgramVisitor::visitStatement;
215
216 ProgramUsage* fUsage;
217 int fDelta;
Brian Osman2e25ff42020-10-15 10:32:04 -0400218 using INHERITED = ProgramVisitor;
219};
220
Ethan Nicholas765d2fe2020-08-26 08:29:55 -0400221class VariableWriteVisitor : public ProgramVisitor {
222public:
223 VariableWriteVisitor(const Variable* var)
224 : fVar(var) {}
225
226 bool visit(const Statement& s) {
227 return this->visitStatement(s);
228 }
229
230 bool visitExpression(const Expression& e) override {
Brian Osman79457ef2020-09-24 15:01:27 -0400231 if (e.is<VariableReference>()) {
Ethan Nicholas765d2fe2020-08-26 08:29:55 -0400232 const VariableReference& ref = e.as<VariableReference>();
Ethan Nicholas453f67f2020-10-09 10:43:45 -0400233 if (ref.variable() == fVar &&
234 (ref.refKind() == VariableReference::RefKind::kWrite ||
235 ref.refKind() == VariableReference::RefKind::kReadWrite ||
236 ref.refKind() == VariableReference::RefKind::kPointer)) {
Ethan Nicholas765d2fe2020-08-26 08:29:55 -0400237 return true;
238 }
239 }
John Stilesd7ab4502020-09-24 22:41:00 -0400240 return INHERITED::visitExpression(e);
Ethan Nicholas765d2fe2020-08-26 08:29:55 -0400241 }
242
243private:
244 const Variable* fVar;
245
John Stiles7571f9e2020-09-02 22:42:33 -0400246 using INHERITED = ProgramVisitor;
Ethan Nicholas765d2fe2020-08-26 08:29:55 -0400247};
248
John Stilesa976da72020-09-25 23:06:26 -0400249// If a caller doesn't care about errors, we can use this trivial reporter that just counts up.
250class TrivialErrorReporter : public ErrorReporter {
251public:
252 void error(int offset, String) override { ++fErrorCount; }
253 int errorCount() override { return fErrorCount; }
John Stiles8d3642e2021-01-22 09:50:04 -0500254 void setErrorCount(int c) override { fErrorCount = c; }
John Stilesa976da72020-09-25 23:06:26 -0400255
256private:
257 int fErrorCount = 0;
258};
259
John Stilesdce4d3e2020-09-25 14:35:13 -0400260// This isn't actually using ProgramVisitor, because it only considers a subset of the fields for
261// any given expression kind. For instance, when indexing an array (e.g. `x[1]`), we only want to
262// know if the base (`x`) is assignable; the index expression (`1`) doesn't need to be.
263class IsAssignableVisitor {
264public:
John Stilesb21fac22020-12-04 15:36:49 -0500265 IsAssignableVisitor(ErrorReporter* errors) : fErrors(errors) {}
John Stilesdce4d3e2020-09-25 14:35:13 -0400266
John Stilesb21fac22020-12-04 15:36:49 -0500267 bool visit(Expression& expr, Analysis::AssignmentInfo* info) {
Ethan Nicholas67a0a8a2021-01-13 12:36:02 -0500268 int oldErrorCount = fErrors->errorCount();
John Stilesdce4d3e2020-09-25 14:35:13 -0400269 this->visitExpression(expr);
John Stilesb21fac22020-12-04 15:36:49 -0500270 if (info) {
271 info->fAssignedVar = fAssignedVar;
John Stilesb21fac22020-12-04 15:36:49 -0500272 }
Ethan Nicholas67a0a8a2021-01-13 12:36:02 -0500273 return fErrors->errorCount() == oldErrorCount;
John Stilesdce4d3e2020-09-25 14:35:13 -0400274 }
275
276 void visitExpression(Expression& expr) {
277 switch (expr.kind()) {
278 case Expression::Kind::kVariableReference: {
279 VariableReference& varRef = expr.as<VariableReference>();
Ethan Nicholas78686922020-10-08 06:46:27 -0400280 const Variable* var = varRef.variable();
Ethan Nicholas041fd0a2020-10-07 16:42:04 -0400281 if (var->modifiers().fFlags & (Modifiers::kConst_Flag | Modifiers::kUniform_Flag |
282 Modifiers::kVarying_Flag)) {
John Stilesa976da72020-09-25 23:06:26 -0400283 fErrors->error(expr.fOffset,
Ethan Nicholase2c49992020-10-05 11:49:11 -0400284 "cannot modify immutable variable '" + var->name() + "'");
John Stilesb21fac22020-12-04 15:36:49 -0500285 } else {
286 SkASSERT(fAssignedVar == nullptr);
287 fAssignedVar = &varRef;
John Stilesdce4d3e2020-09-25 14:35:13 -0400288 }
289 break;
290 }
291 case Expression::Kind::kFieldAccess:
Ethan Nicholas7a95b202020-10-09 11:55:40 -0400292 this->visitExpression(*expr.as<FieldAccess>().base());
John Stilesdce4d3e2020-09-25 14:35:13 -0400293 break;
294
295 case Expression::Kind::kSwizzle: {
296 const Swizzle& swizzle = expr.as<Swizzle>();
297 this->checkSwizzleWrite(swizzle);
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400298 this->visitExpression(*swizzle.base());
John Stilesdce4d3e2020-09-25 14:35:13 -0400299 break;
300 }
John Stiles47c0a742021-02-09 09:30:35 -0500301 case Expression::Kind::kIndex:
302 this->visitExpression(*expr.as<IndexExpression>().base());
John Stilesdce4d3e2020-09-25 14:35:13 -0400303 break;
John Stiles47c0a742021-02-09 09:30:35 -0500304
John Stilesdce4d3e2020-09-25 14:35:13 -0400305 default:
John Stilesa976da72020-09-25 23:06:26 -0400306 fErrors->error(expr.fOffset, "cannot assign to this expression");
John Stilesdce4d3e2020-09-25 14:35:13 -0400307 break;
308 }
309 }
310
311private:
312 void checkSwizzleWrite(const Swizzle& swizzle) {
313 int bits = 0;
John Stiles6e88e042021-02-19 14:09:38 -0500314 for (int8_t idx : swizzle.components()) {
315 SkASSERT(idx >= SwizzleComponent::X && idx <= SwizzleComponent::W);
John Stilesdce4d3e2020-09-25 14:35:13 -0400316 int bit = 1 << idx;
317 if (bits & bit) {
John Stilesa976da72020-09-25 23:06:26 -0400318 fErrors->error(swizzle.fOffset,
319 "cannot write to the same swizzle field more than once");
John Stilesdce4d3e2020-09-25 14:35:13 -0400320 break;
321 }
322 bits |= bit;
323 }
324 }
325
John Stilesa976da72020-09-25 23:06:26 -0400326 ErrorReporter* fErrors;
John Stilesb21fac22020-12-04 15:36:49 -0500327 VariableReference* fAssignedVar = nullptr;
John Stilesdce4d3e2020-09-25 14:35:13 -0400328
329 using INHERITED = ProgramVisitor;
330};
331
John Stiles642cde22021-02-23 14:57:01 -0500332class SwitchCaseContainsExit : public ProgramVisitor {
333public:
334 SwitchCaseContainsExit(bool conditionalExits) : fConditionalExits(conditionalExits) {}
335
336 bool visitStatement(const Statement& stmt) override {
337 switch (stmt.kind()) {
338 case Statement::Kind::kBlock:
339 return INHERITED::visitStatement(stmt);
340
341 case Statement::Kind::kReturn:
342 // Returns are an early exit regardless of the surrounding control structures.
343 return fConditionalExits ? fInConditional : !fInConditional;
344
345 case Statement::Kind::kContinue:
346 // Continues are an early exit from switches, but not loops.
347 return !fInLoop &&
348 (fConditionalExits ? fInConditional : !fInConditional);
349
350 case Statement::Kind::kBreak:
351 // Breaks cannot escape from switches or loops.
352 return !fInLoop && !fInSwitch &&
353 (fConditionalExits ? fInConditional : !fInConditional);
354
355 case Statement::Kind::kIf: {
356 ++fInConditional;
357 bool result = INHERITED::visitStatement(stmt);
358 --fInConditional;
359 return result;
360 }
361
362 case Statement::Kind::kFor:
363 case Statement::Kind::kDo: {
364 // Loops are treated as conditionals because a loop could potentially execute zero
365 // times. We don't have a straightforward way to determine that a loop definitely
366 // executes at least once.
367 ++fInConditional;
368 ++fInLoop;
369 bool result = INHERITED::visitStatement(stmt);
370 --fInLoop;
371 --fInConditional;
372 return result;
373 }
374
375 case Statement::Kind::kSwitch: {
376 ++fInSwitch;
377 bool result = INHERITED::visitStatement(stmt);
378 --fInSwitch;
379 return result;
380 }
381
382 default:
383 return false;
384 }
385 }
386
387 bool fConditionalExits = false;
388 int fInConditional = 0;
389 int fInLoop = 0;
390 int fInSwitch = 0;
391 using INHERITED = ProgramVisitor;
392};
393
John Stilesa6841be2020-08-06 14:11:56 -0400394} // namespace
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400395
396////////////////////////////////////////////////////////////////////////////////
397// Analysis
398
Brian Osman1298bc42020-06-30 13:39:35 -0400399SampleUsage Analysis::GetSampleUsage(const Program& program, const Variable& fp) {
John Stiles933abe32020-08-28 11:58:40 -0400400 MergeSampleUsageVisitor visitor(*program.fContext, fp);
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400401 return visitor.visit(program);
402}
403
Brian Osman92aac1e2020-08-05 16:48:58 -0400404bool Analysis::ReferencesBuiltin(const Program& program, int builtin) {
405 BuiltinVariableVisitor visitor(builtin);
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400406 return visitor.visit(program);
407}
408
Brian Osman92aac1e2020-08-05 16:48:58 -0400409bool Analysis::ReferencesSampleCoords(const Program& program) {
410 return Analysis::ReferencesBuiltin(program, SK_MAIN_COORDS_BUILTIN);
411}
412
413bool Analysis::ReferencesFragCoords(const Program& program) {
414 return Analysis::ReferencesBuiltin(program, SK_FRAGCOORD_BUILTIN);
415}
416
John Stiles9b9415e2020-11-23 14:48:06 -0500417int Analysis::NodeCountUpToLimit(const FunctionDefinition& function, int limit) {
418 return NodeCountVisitor{limit}.visit(*function.body());
Ethan Nicholas6e0fa402020-08-20 14:08:23 -0400419}
420
John Stiles642cde22021-02-23 14:57:01 -0500421bool Analysis::SwitchCaseContainsUnconditionalExit(Statement& stmt) {
422 return SwitchCaseContainsExit{/*conditionalExits=*/false}.visitStatement(stmt);
423}
424
425bool Analysis::SwitchCaseContainsConditionalExit(Statement& stmt) {
426 return SwitchCaseContainsExit{/*conditionalExits=*/true}.visitStatement(stmt);
427}
428
Brian Osman010ce6a2020-10-19 16:34:10 -0400429std::unique_ptr<ProgramUsage> Analysis::GetUsage(const Program& program) {
430 auto usage = std::make_unique<ProgramUsage>();
431 ProgramUsageVisitor addRefs(usage.get(), /*delta=*/+1);
432 addRefs.visit(program);
433 return usage;
434}
435
Brian Osman0006ad02020-11-18 15:38:39 -0500436std::unique_ptr<ProgramUsage> Analysis::GetUsage(const LoadedModule& module) {
437 auto usage = std::make_unique<ProgramUsage>();
438 ProgramUsageVisitor addRefs(usage.get(), /*delta=*/+1);
439 for (const auto& element : module.fElements) {
440 addRefs.visitProgramElement(*element);
441 }
442 return usage;
443}
444
Brian Osman010ce6a2020-10-19 16:34:10 -0400445ProgramUsage::VariableCounts ProgramUsage::get(const Variable& v) const {
446 VariableCounts result = { 0, v.initialValue() ? 1 : 0 };
447 if (const VariableCounts* counts = fVariableCounts.find(&v)) {
448 result.fRead += counts->fRead;
449 result.fWrite += counts->fWrite;
450 }
451 return result;
452}
453
454bool ProgramUsage::isDead(const Variable& v) const {
455 const Modifiers& modifiers = v.modifiers();
456 VariableCounts counts = this->get(v);
457 if ((v.storage() != Variable::Storage::kLocal && counts.fRead) ||
458 (modifiers.fFlags & (Modifiers::kIn_Flag | Modifiers::kOut_Flag | Modifiers::kUniform_Flag |
459 Modifiers::kVarying_Flag))) {
460 return false;
461 }
Brian Osman9cb3f982021-02-18 12:44:57 -0500462 return !counts.fWrite || !counts.fRead;
Brian Osman010ce6a2020-10-19 16:34:10 -0400463}
464
465int ProgramUsage::get(const FunctionDeclaration& f) const {
466 const int* count = fCallCounts.find(&f);
467 return count ? *count : 0;
468}
469
470void ProgramUsage::replace(const Expression* oldExpr, const Expression* newExpr) {
471 if (oldExpr) {
472 ProgramUsageVisitor subRefs(this, /*delta=*/-1);
473 subRefs.visitExpression(*oldExpr);
474 }
475 if (newExpr) {
476 ProgramUsageVisitor addRefs(this, /*delta=*/+1);
477 addRefs.visitExpression(*newExpr);
478 }
479}
480
481void ProgramUsage::add(const Statement* stmt) {
482 ProgramUsageVisitor addRefs(this, /*delta=*/+1);
483 addRefs.visitStatement(*stmt);
484}
485
486void ProgramUsage::remove(const Expression* expr) {
487 ProgramUsageVisitor subRefs(this, /*delta=*/-1);
488 subRefs.visitExpression(*expr);
489}
490
491void ProgramUsage::remove(const Statement* stmt) {
492 ProgramUsageVisitor subRefs(this, /*delta=*/-1);
493 subRefs.visitStatement(*stmt);
494}
495
496void ProgramUsage::remove(const ProgramElement& element) {
497 ProgramUsageVisitor subRefs(this, /*delta=*/-1);
498 subRefs.visitProgramElement(element);
Brian Osman2e25ff42020-10-15 10:32:04 -0400499}
500
Ethan Nicholas765d2fe2020-08-26 08:29:55 -0400501bool Analysis::StatementWritesToVariable(const Statement& stmt, const Variable& var) {
502 return VariableWriteVisitor(&var).visit(stmt);
503}
504
John Stilesb21fac22020-12-04 15:36:49 -0500505bool Analysis::IsAssignable(Expression& expr, AssignmentInfo* info, ErrorReporter* errors) {
John Stilesa976da72020-09-25 23:06:26 -0400506 TrivialErrorReporter trivialErrors;
John Stilesb21fac22020-12-04 15:36:49 -0500507 return IsAssignableVisitor{errors ? errors : &trivialErrors}.visit(expr, info);
John Stilesdce4d3e2020-09-25 14:35:13 -0400508}
509
John Stiles47c0a742021-02-09 09:30:35 -0500510void Analysis::UpdateRefKind(Expression* expr, VariableRefKind refKind) {
511 class RefKindWriter : public ProgramWriter {
512 public:
513 RefKindWriter(VariableReference::RefKind refKind) : fRefKind(refKind) {}
514
515 bool visitExpression(Expression& expr) override {
516 if (expr.is<VariableReference>()) {
517 expr.as<VariableReference>().setRefKind(fRefKind);
518 }
519 return INHERITED::visitExpression(expr);
520 }
521
522 private:
523 VariableReference::RefKind fRefKind;
524
525 using INHERITED = ProgramWriter;
526 };
527
528 RefKindWriter{refKind}.visitExpression(*expr);
529}
530
John Stiles516704b2021-02-26 15:01:57 -0500531bool Analysis::MakeAssignmentExpr(Expression* expr,
532 VariableReference::RefKind kind,
533 ErrorReporter* errors) {
534 Analysis::AssignmentInfo info;
535 if (!Analysis::IsAssignable(*expr, &info, errors)) {
536 return false;
537 }
538 if (!info.fAssignedVar) {
539 errors->error(expr->fOffset, "can't assign to expression '" + expr->description() + "'");
540 return false;
541 }
542 info.fAssignedVar->setRefKind(kind);
543 return true;
544}
545
John Stilesc30fbca2020-11-19 16:25:49 -0500546bool Analysis::IsTrivialExpression(const Expression& expr) {
547 return expr.is<IntLiteral>() ||
548 expr.is<FloatLiteral>() ||
549 expr.is<BoolLiteral>() ||
550 expr.is<VariableReference>() ||
551 (expr.is<Swizzle>() &&
552 IsTrivialExpression(*expr.as<Swizzle>().base())) ||
553 (expr.is<FieldAccess>() &&
554 IsTrivialExpression(*expr.as<FieldAccess>().base())) ||
555 (expr.is<Constructor>() &&
556 expr.as<Constructor>().arguments().size() == 1 &&
557 IsTrivialExpression(*expr.as<Constructor>().arguments().front())) ||
558 (expr.is<Constructor>() &&
559 expr.isConstantOrUniform()) ||
560 (expr.is<IndexExpression>() &&
561 expr.as<IndexExpression>().index()->is<IntLiteral>() &&
562 IsTrivialExpression(*expr.as<IndexExpression>().base()));
563}
564
John Stiles95d0bad2021-03-01 17:02:28 -0500565bool Analysis::IsSelfAssignment(const Expression& left, const Expression& right) {
566 if (left.kind() != right.kind() || left.type() != right.type()) {
567 return false;
568 }
569
John Stiles786d42c2021-03-02 09:57:28 -0500570 // This isn't a fully exhaustive list of expressions that could be involved in a self-
571 // assignment, particularly when arrays are involved; for instance, `x[y+1] = x[y+1]` isn't
572 // detected because we don't look at BinaryExpressions. Since this is intended to be used for
573 // optimization purposes, handling the common cases is sufficient.
John Stiles95d0bad2021-03-01 17:02:28 -0500574 switch (left.kind()) {
575 case Expression::Kind::kIntLiteral:
576 return left.as<IntLiteral>().value() == right.as<IntLiteral>().value();
577
578 case Expression::Kind::kFieldAccess:
579 return left.as<FieldAccess>().fieldIndex() == right.as<FieldAccess>().fieldIndex() &&
580 IsSelfAssignment(*left.as<FieldAccess>().base(),
581 *right.as<FieldAccess>().base());
582
583 case Expression::Kind::kIndex:
584 return IsSelfAssignment(*left.as<IndexExpression>().index(),
585 *right.as<IndexExpression>().index()) &&
586 IsSelfAssignment(*left.as<IndexExpression>().base(),
587 *right.as<IndexExpression>().base());
588
589 case Expression::Kind::kSwizzle:
590 return left.as<Swizzle>().components() == right.as<Swizzle>().components() &&
591 IsSelfAssignment(*left.as<Swizzle>().base(), *right.as<Swizzle>().base());
592
593 case Expression::Kind::kVariableReference:
594 return left.as<VariableReference>().variable() ==
595 right.as<VariableReference>().variable();
596
597 default:
598 return false;
599 }
600}
601
John Stiles232b4ce2021-03-01 22:14:22 -0500602static const char* invalid_for_ES2(int offset,
603 const Statement* loopInitializer,
604 const Expression* loopTest,
605 const Expression* loopNext,
606 const Statement* loopStatement,
Brian Osman77ba8102021-01-12 17:15:30 -0500607 Analysis::UnrollableLoopInfo& loopInfo) {
608 auto getConstant = [&](const std::unique_ptr<Expression>& expr, double* val) {
609 if (!expr->isCompileTimeConstant()) {
610 return false;
611 }
Brian Osman6c7910e2021-01-14 09:50:52 -0500612 if (!expr->type().isNumber()) {
Brian Osman77ba8102021-01-12 17:15:30 -0500613 SkDEBUGFAIL("unexpected constant type");
614 return false;
615 }
616
617 *val = expr->type().isInteger() ? static_cast<double>(expr->getConstantInt())
618 : static_cast<double>(expr->getConstantFloat());
619 return true;
620 };
621
622 //
623 // init_declaration has the form: type_specifier identifier = constant_expression
624 //
John Stiles232b4ce2021-03-01 22:14:22 -0500625 if (!loopInitializer) {
Brian Osman77ba8102021-01-12 17:15:30 -0500626 return "missing init declaration";
627 }
John Stiles232b4ce2021-03-01 22:14:22 -0500628 if (!loopInitializer->is<VarDeclaration>()) {
Brian Osman77ba8102021-01-12 17:15:30 -0500629 return "invalid init declaration";
630 }
John Stiles232b4ce2021-03-01 22:14:22 -0500631 const VarDeclaration& initDecl = loopInitializer->as<VarDeclaration>();
Brian Osman6c7910e2021-01-14 09:50:52 -0500632 if (!initDecl.baseType().isNumber()) {
Brian Osman77ba8102021-01-12 17:15:30 -0500633 return "invalid type for loop index";
634 }
635 if (initDecl.arraySize() != 0) {
636 return "invalid type for loop index";
637 }
638 if (!initDecl.value()) {
639 return "missing loop index initializer";
640 }
641 if (!getConstant(initDecl.value(), &loopInfo.fStart)) {
642 return "loop index initializer must be a constant expression";
643 }
644
645 loopInfo.fIndex = &initDecl.var();
646
647 auto is_loop_index = [&](const std::unique_ptr<Expression>& expr) {
648 return expr->is<VariableReference>() &&
649 expr->as<VariableReference>().variable() == loopInfo.fIndex;
650 };
651
652 //
653 // condition has the form: loop_index relational_operator constant_expression
654 //
John Stiles232b4ce2021-03-01 22:14:22 -0500655 if (!loopTest) {
Brian Osman77ba8102021-01-12 17:15:30 -0500656 return "missing condition";
657 }
John Stiles232b4ce2021-03-01 22:14:22 -0500658 if (!loopTest->is<BinaryExpression>()) {
Brian Osman77ba8102021-01-12 17:15:30 -0500659 return "invalid condition";
660 }
John Stiles232b4ce2021-03-01 22:14:22 -0500661 const BinaryExpression& cond = loopTest->as<BinaryExpression>();
Brian Osman77ba8102021-01-12 17:15:30 -0500662 if (!is_loop_index(cond.left())) {
663 return "expected loop index on left hand side of condition";
664 }
665 // relational_operator is one of: > >= < <= == or !=
John Stiles45990502021-02-16 10:55:27 -0500666 switch (cond.getOperator().kind()) {
Brian Osman77ba8102021-01-12 17:15:30 -0500667 case Token::Kind::TK_GT:
668 case Token::Kind::TK_GTEQ:
669 case Token::Kind::TK_LT:
670 case Token::Kind::TK_LTEQ:
671 case Token::Kind::TK_EQEQ:
672 case Token::Kind::TK_NEQ:
673 break;
674 default:
675 return "invalid relational operator";
676 }
677 double loopEnd = 0;
678 if (!getConstant(cond.right(), &loopEnd)) {
679 return "loop index must be compared with a constant expression";
680 }
681
682 //
683 // expression has one of the following forms:
684 // loop_index++
685 // loop_index--
686 // loop_index += constant_expression
687 // loop_index -= constant_expression
688 // The spec doesn't mention prefix increment and decrement, but there is some consensus that
689 // it's an oversight, so we allow those as well.
690 //
John Stiles232b4ce2021-03-01 22:14:22 -0500691 if (!loopNext) {
Brian Osman77ba8102021-01-12 17:15:30 -0500692 return "missing loop expression";
693 }
John Stiles232b4ce2021-03-01 22:14:22 -0500694 switch (loopNext->kind()) {
Brian Osman77ba8102021-01-12 17:15:30 -0500695 case Expression::Kind::kBinary: {
John Stiles232b4ce2021-03-01 22:14:22 -0500696 const BinaryExpression& next = loopNext->as<BinaryExpression>();
Brian Osman77ba8102021-01-12 17:15:30 -0500697 if (!is_loop_index(next.left())) {
698 return "expected loop index in loop expression";
699 }
700 if (!getConstant(next.right(), &loopInfo.fDelta)) {
701 return "loop index must be modified by a constant expression";
702 }
John Stiles45990502021-02-16 10:55:27 -0500703 switch (next.getOperator().kind()) {
Brian Osman77ba8102021-01-12 17:15:30 -0500704 case Token::Kind::TK_PLUSEQ: break;
705 case Token::Kind::TK_MINUSEQ: loopInfo.fDelta = -loopInfo.fDelta; break;
706 default:
707 return "invalid operator in loop expression";
708 }
709 } break;
710 case Expression::Kind::kPrefix: {
John Stiles232b4ce2021-03-01 22:14:22 -0500711 const PrefixExpression& next = loopNext->as<PrefixExpression>();
Brian Osman77ba8102021-01-12 17:15:30 -0500712 if (!is_loop_index(next.operand())) {
713 return "expected loop index in loop expression";
714 }
John Stiles45990502021-02-16 10:55:27 -0500715 switch (next.getOperator().kind()) {
Brian Osman77ba8102021-01-12 17:15:30 -0500716 case Token::Kind::TK_PLUSPLUS: loopInfo.fDelta = 1; break;
717 case Token::Kind::TK_MINUSMINUS: loopInfo.fDelta = -1; break;
718 default:
719 return "invalid operator in loop expression";
720 }
721 } break;
722 case Expression::Kind::kPostfix: {
John Stiles232b4ce2021-03-01 22:14:22 -0500723 const PostfixExpression& next = loopNext->as<PostfixExpression>();
Brian Osman77ba8102021-01-12 17:15:30 -0500724 if (!is_loop_index(next.operand())) {
725 return "expected loop index in loop expression";
726 }
John Stiles45990502021-02-16 10:55:27 -0500727 switch (next.getOperator().kind()) {
Brian Osman77ba8102021-01-12 17:15:30 -0500728 case Token::Kind::TK_PLUSPLUS: loopInfo.fDelta = 1; break;
729 case Token::Kind::TK_MINUSMINUS: loopInfo.fDelta = -1; break;
730 default:
731 return "invalid operator in loop expression";
732 }
733 } break;
734 default:
735 return "invalid loop expression";
736 }
737
738 //
739 // Within the body of the loop, the loop index is not statically assigned to, nor is it used as
740 // argument to a function 'out' or 'inout' parameter.
741 //
John Stiles232b4ce2021-03-01 22:14:22 -0500742 if (Analysis::StatementWritesToVariable(*loopStatement, initDecl.var())) {
Brian Osman77ba8102021-01-12 17:15:30 -0500743 return "loop index must not be modified within body of the loop";
744 }
745
746 // Finally, compute the iteration count, based on the bounds, and the termination operator.
747 constexpr int kMaxUnrollableLoopLength = 128;
748 loopInfo.fCount = 0;
749
750 double val = loopInfo.fStart;
751 auto evalCond = [&]() {
John Stiles45990502021-02-16 10:55:27 -0500752 switch (cond.getOperator().kind()) {
Brian Osman77ba8102021-01-12 17:15:30 -0500753 case Token::Kind::TK_GT: return val > loopEnd;
754 case Token::Kind::TK_GTEQ: return val >= loopEnd;
755 case Token::Kind::TK_LT: return val < loopEnd;
756 case Token::Kind::TK_LTEQ: return val <= loopEnd;
757 case Token::Kind::TK_EQEQ: return val == loopEnd;
758 case Token::Kind::TK_NEQ: return val != loopEnd;
759 default: SkUNREACHABLE;
760 }
761 };
762
763 for (loopInfo.fCount = 0; loopInfo.fCount <= kMaxUnrollableLoopLength; ++loopInfo.fCount) {
764 if (!evalCond()) {
765 break;
766 }
767 val += loopInfo.fDelta;
768 }
769
770 if (loopInfo.fCount > kMaxUnrollableLoopLength) {
771 return "loop must guarantee termination in fewer iterations";
772 }
773
774 return nullptr; // All checks pass
775}
776
John Stiles232b4ce2021-03-01 22:14:22 -0500777bool Analysis::ForLoopIsValidForES2(int offset,
778 const Statement* loopInitializer,
779 const Expression* loopTest,
780 const Expression* loopNext,
781 const Statement* loopStatement,
Brian Osman77ba8102021-01-12 17:15:30 -0500782 Analysis::UnrollableLoopInfo* outLoopInfo,
783 ErrorReporter* errors) {
784 UnrollableLoopInfo ignored,
785 *loopInfo = outLoopInfo ? outLoopInfo : &ignored;
John Stiles232b4ce2021-03-01 22:14:22 -0500786 if (const char* msg = invalid_for_ES2(
787 offset, loopInitializer, loopTest, loopNext, loopStatement, *loopInfo)) {
Brian Osman77ba8102021-01-12 17:15:30 -0500788 if (errors) {
John Stiles232b4ce2021-03-01 22:14:22 -0500789 errors->error(offset, msg);
Brian Osman77ba8102021-01-12 17:15:30 -0500790 }
791 return false;
792 }
793 return true;
794}
795
Brian Osman7b361492021-02-25 11:25:30 -0500796// Checks for ES2 constant-expression rules, and (optionally) constant-index-expression rules
797// (if loopIndices is non-nullptr)
798class ConstantExpressionVisitor : public ProgramVisitor {
Brian Osmanea485e52021-01-15 13:20:32 -0500799public:
Brian Osman7b361492021-02-25 11:25:30 -0500800 ConstantExpressionVisitor(const std::set<const Variable*>* loopIndices)
Brian Osmanea485e52021-01-15 13:20:32 -0500801 : fLoopIndices(loopIndices) {}
802
803 bool visitExpression(const Expression& e) override {
804 // A constant-(index)-expression is one of...
805 switch (e.kind()) {
806 // ... a literal value
807 case Expression::Kind::kBoolLiteral:
808 case Expression::Kind::kIntLiteral:
809 case Expression::Kind::kFloatLiteral:
810 return false;
811
Brian Osman7b361492021-02-25 11:25:30 -0500812 // ... a global or local variable qualified as 'const', excluding function parameters.
813 // ... loop indices as defined in section 4. [constant-index-expression]
814 case Expression::Kind::kVariableReference: {
815 const Variable* v = e.as<VariableReference>().variable();
816 if ((v->storage() == Variable::Storage::kGlobal ||
817 v->storage() == Variable::Storage::kLocal) &&
818 (v->modifiers().fFlags & Modifiers::kConst_Flag)) {
819 return false;
820 }
821 return !fLoopIndices || fLoopIndices->find(v) == fLoopIndices->end();
822 }
Brian Osmanea485e52021-01-15 13:20:32 -0500823
824 // ... expressions composed of both of the above
825 case Expression::Kind::kBinary:
826 case Expression::Kind::kConstructor:
827 case Expression::Kind::kFieldAccess:
828 case Expression::Kind::kIndex:
829 case Expression::Kind::kPrefix:
830 case Expression::Kind::kPostfix:
831 case Expression::Kind::kSwizzle:
832 case Expression::Kind::kTernary:
833 return INHERITED::visitExpression(e);
834
Brian Osman7b361492021-02-25 11:25:30 -0500835 // These are completely disallowed in SkSL constant-(index)-expressions. GLSL allows
Brian Osmanea485e52021-01-15 13:20:32 -0500836 // calls to built-in functions where the arguments are all constant-expressions, but
837 // we don't guarantee that behavior. (skbug.com/10835)
838 case Expression::Kind::kExternalFunctionCall:
839 case Expression::Kind::kFunctionCall:
840 return true;
841
842 // These should never appear in final IR
843 case Expression::Kind::kDefined:
844 case Expression::Kind::kExternalFunctionReference:
845 case Expression::Kind::kFunctionReference:
846 case Expression::Kind::kSetting:
847 case Expression::Kind::kTypeReference:
848 default:
849 SkDEBUGFAIL("Unexpected expression type");
850 return true;
851 }
852 }
853
854private:
855 const std::set<const Variable*>* fLoopIndices;
856 using INHERITED = ProgramVisitor;
857};
858
859class ES2IndexingVisitor : public ProgramVisitor {
860public:
861 ES2IndexingVisitor(ErrorReporter& errors) : fErrors(errors) {}
862
863 bool visitStatement(const Statement& s) override {
864 if (s.is<ForStatement>()) {
865 const ForStatement& f = s.as<ForStatement>();
866 SkASSERT(f.initializer() && f.initializer()->is<VarDeclaration>());
867 const Variable* var = &f.initializer()->as<VarDeclaration>().var();
868 auto [iter, inserted] = fLoopIndices.insert(var);
869 SkASSERT(inserted);
870 bool result = this->visitStatement(*f.statement());
871 fLoopIndices.erase(iter);
872 return result;
873 }
874 return INHERITED::visitStatement(s);
875 }
876
877 bool visitExpression(const Expression& e) override {
878 if (e.is<IndexExpression>()) {
879 const IndexExpression& i = e.as<IndexExpression>();
Brian Osman7b361492021-02-25 11:25:30 -0500880 ConstantExpressionVisitor indexerInvalid(&fLoopIndices);
Brian Osmanea485e52021-01-15 13:20:32 -0500881 if (indexerInvalid.visitExpression(*i.index())) {
882 fErrors.error(i.fOffset, "index expression must be constant");
883 return true;
884 }
885 }
886 return INHERITED::visitExpression(e);
887 }
888
889 using ProgramVisitor::visitProgramElement;
890
891private:
892 ErrorReporter& fErrors;
893 std::set<const Variable*> fLoopIndices;
894 using INHERITED = ProgramVisitor;
895};
896
897
898void Analysis::ValidateIndexingForES2(const ProgramElement& pe, ErrorReporter& errors) {
899 ES2IndexingVisitor visitor(errors);
900 visitor.visitProgramElement(pe);
901}
902
Brian Osman7b361492021-02-25 11:25:30 -0500903bool Analysis::IsConstantExpression(const Expression& expr) {
904 ConstantExpressionVisitor visitor(/*loopIndices=*/nullptr);
905 return !visitor.visitExpression(expr);
906}
907
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400908////////////////////////////////////////////////////////////////////////////////
909// ProgramVisitor
910
Brian Osman133724c2020-10-28 14:14:39 -0400911bool ProgramVisitor::visit(const Program& program) {
912 for (const ProgramElement* pe : program.elements()) {
Brian Osman1179fcf2020-10-08 16:04:40 -0400913 if (this->visitProgramElement(*pe)) {
John Stiles933abe32020-08-28 11:58:40 -0400914 return true;
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400915 }
916 }
John Stiles933abe32020-08-28 11:58:40 -0400917 return false;
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400918}
919
John Stiles70b82422020-09-30 10:55:12 -0400920template <typename PROG, typename EXPR, typename STMT, typename ELEM>
921bool TProgramVisitor<PROG, EXPR, STMT, ELEM>::visitExpression(EXPR e) {
922 switch (e.kind()) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400923 case Expression::Kind::kBoolLiteral:
924 case Expression::Kind::kDefined:
Brian Osmanbe0b3b72021-01-06 14:27:35 -0500925 case Expression::Kind::kExternalFunctionReference:
Ethan Nicholase6592142020-09-08 10:22:09 -0400926 case Expression::Kind::kFloatLiteral:
927 case Expression::Kind::kFunctionReference:
928 case Expression::Kind::kIntLiteral:
Ethan Nicholase6592142020-09-08 10:22:09 -0400929 case Expression::Kind::kSetting:
930 case Expression::Kind::kTypeReference:
931 case Expression::Kind::kVariableReference:
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400932 // Leaf expressions return false
933 return false;
John Stiles70b82422020-09-30 10:55:12 -0400934
Ethan Nicholase6592142020-09-08 10:22:09 -0400935 case Expression::Kind::kBinary: {
John Stiles70b82422020-09-30 10:55:12 -0400936 auto& b = e.template as<BinaryExpression>();
John Stiles2d4f9592020-10-30 10:29:12 -0400937 return (b.left() && this->visitExpression(*b.left())) ||
938 (b.right() && this->visitExpression(*b.right()));
John Stiles70b82422020-09-30 10:55:12 -0400939 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400940 case Expression::Kind::kConstructor: {
John Stiles70b82422020-09-30 10:55:12 -0400941 auto& c = e.template as<Constructor>();
942 for (auto& arg : c.arguments()) {
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400943 if (this->visitExpression(*arg)) { return true; }
944 }
John Stiles70b82422020-09-30 10:55:12 -0400945 return false;
946 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400947 case Expression::Kind::kExternalFunctionCall: {
John Stiles70b82422020-09-30 10:55:12 -0400948 auto& c = e.template as<ExternalFunctionCall>();
Ethan Nicholas6e86ec92020-09-30 14:29:56 -0400949 for (auto& arg : c.arguments()) {
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400950 if (this->visitExpression(*arg)) { return true; }
951 }
John Stiles70b82422020-09-30 10:55:12 -0400952 return false;
953 }
John Stilesd7ab4502020-09-24 22:41:00 -0400954 case Expression::Kind::kFieldAccess:
Ethan Nicholas7a95b202020-10-09 11:55:40 -0400955 return this->visitExpression(*e.template as<FieldAccess>().base());
John Stiles70b82422020-09-30 10:55:12 -0400956
Ethan Nicholase6592142020-09-08 10:22:09 -0400957 case Expression::Kind::kFunctionCall: {
John Stiles70b82422020-09-30 10:55:12 -0400958 auto& c = e.template as<FunctionCall>();
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400959 for (auto& arg : c.arguments()) {
Brian Osman010ce6a2020-10-19 16:34:10 -0400960 if (arg && this->visitExpression(*arg)) { return true; }
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400961 }
John Stiles70b82422020-09-30 10:55:12 -0400962 return false;
963 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400964 case Expression::Kind::kIndex: {
John Stiles70b82422020-09-30 10:55:12 -0400965 auto& i = e.template as<IndexExpression>();
Ethan Nicholas2a4952d2020-10-08 15:35:56 -0400966 return this->visitExpression(*i.base()) || this->visitExpression(*i.index());
John Stiles70b82422020-09-30 10:55:12 -0400967 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400968 case Expression::Kind::kPostfix:
Ethan Nicholas444ccc62020-10-09 10:16:22 -0400969 return this->visitExpression(*e.template as<PostfixExpression>().operand());
John Stiles70b82422020-09-30 10:55:12 -0400970
Ethan Nicholase6592142020-09-08 10:22:09 -0400971 case Expression::Kind::kPrefix:
Ethan Nicholas444ccc62020-10-09 10:16:22 -0400972 return this->visitExpression(*e.template as<PrefixExpression>().operand());
John Stiles70b82422020-09-30 10:55:12 -0400973
Brian Osman010ce6a2020-10-19 16:34:10 -0400974 case Expression::Kind::kSwizzle: {
975 auto& s = e.template as<Swizzle>();
976 return s.base() && this->visitExpression(*s.base());
977 }
John Stiles70b82422020-09-30 10:55:12 -0400978
Ethan Nicholase6592142020-09-08 10:22:09 -0400979 case Expression::Kind::kTernary: {
John Stiles70b82422020-09-30 10:55:12 -0400980 auto& t = e.template as<TernaryExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400981 return this->visitExpression(*t.test()) ||
982 (t.ifTrue() && this->visitExpression(*t.ifTrue())) ||
983 (t.ifFalse() && this->visitExpression(*t.ifFalse()));
John Stiles70b82422020-09-30 10:55:12 -0400984 }
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400985 default:
986 SkUNREACHABLE;
987 }
988}
989
John Stiles70b82422020-09-30 10:55:12 -0400990template <typename PROG, typename EXPR, typename STMT, typename ELEM>
991bool TProgramVisitor<PROG, EXPR, STMT, ELEM>::visitStatement(STMT s) {
992 switch (s.kind()) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400993 case Statement::Kind::kBreak:
994 case Statement::Kind::kContinue:
995 case Statement::Kind::kDiscard:
John Stiles98c1f822020-09-09 14:18:53 -0400996 case Statement::Kind::kInlineMarker:
Ethan Nicholase6592142020-09-08 10:22:09 -0400997 case Statement::Kind::kNop:
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400998 // Leaf statements just return false
999 return false;
John Stiles70b82422020-09-30 10:55:12 -04001000
Ethan Nicholase6592142020-09-08 10:22:09 -04001001 case Statement::Kind::kBlock:
John Stiles70b82422020-09-30 10:55:12 -04001002 for (auto& stmt : s.template as<Block>().children()) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001003 if (stmt && this->visitStatement(*stmt)) {
Ethan Nicholas7bd60432020-09-25 14:31:59 -04001004 return true;
1005 }
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001006 }
1007 return false;
John Stiles70b82422020-09-30 10:55:12 -04001008
Ethan Nicholase6592142020-09-08 10:22:09 -04001009 case Statement::Kind::kDo: {
John Stiles70b82422020-09-30 10:55:12 -04001010 auto& d = s.template as<DoStatement>();
1011 return this->visitExpression(*d.test()) || this->visitStatement(*d.statement());
1012 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001013 case Statement::Kind::kExpression:
John Stiles70b82422020-09-30 10:55:12 -04001014 return this->visitExpression(*s.template as<ExpressionStatement>().expression());
1015
Ethan Nicholase6592142020-09-08 10:22:09 -04001016 case Statement::Kind::kFor: {
John Stiles70b82422020-09-30 10:55:12 -04001017 auto& f = s.template as<ForStatement>();
Ethan Nicholas0d31ed52020-10-05 14:47:09 -04001018 return (f.initializer() && this->visitStatement(*f.initializer())) ||
1019 (f.test() && this->visitExpression(*f.test())) ||
1020 (f.next() && this->visitExpression(*f.next())) ||
1021 this->visitStatement(*f.statement());
John Stiles70b82422020-09-30 10:55:12 -04001022 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001023 case Statement::Kind::kIf: {
John Stiles70b82422020-09-30 10:55:12 -04001024 auto& i = s.template as<IfStatement>();
Brian Osman5567a602020-10-27 09:52:39 -04001025 return (i.test() && this->visitExpression(*i.test())) ||
Brian Osman010ce6a2020-10-19 16:34:10 -04001026 (i.ifTrue() && this->visitStatement(*i.ifTrue())) ||
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001027 (i.ifFalse() && this->visitStatement(*i.ifFalse()));
John Stiles70b82422020-09-30 10:55:12 -04001028 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001029 case Statement::Kind::kReturn: {
John Stiles70b82422020-09-30 10:55:12 -04001030 auto& r = s.template as<ReturnStatement>();
Ethan Nicholas2a4952d2020-10-08 15:35:56 -04001031 return r.expression() && this->visitExpression(*r.expression());
John Stiles70b82422020-09-30 10:55:12 -04001032 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001033 case Statement::Kind::kSwitch: {
John Stiles70b82422020-09-30 10:55:12 -04001034 auto& sw = s.template as<SwitchStatement>();
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001035 if (this->visitExpression(*sw.value())) {
John Stiles70b82422020-09-30 10:55:12 -04001036 return true;
1037 }
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001038 for (const auto& c : sw.cases()) {
John Stiles2d4f9592020-10-30 10:29:12 -04001039 if (c->value() && this->visitExpression(*c->value())) {
John Stiles70b82422020-09-30 10:55:12 -04001040 return true;
1041 }
John Stiles2d4f9592020-10-30 10:29:12 -04001042 for (auto& st : c->statements()) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001043 if (st && this->visitStatement(*st)) {
John Stiles70b82422020-09-30 10:55:12 -04001044 return true;
1045 }
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001046 }
1047 }
John Stiles70b82422020-09-30 10:55:12 -04001048 return false;
1049 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001050 case Statement::Kind::kVarDeclaration: {
John Stiles70b82422020-09-30 10:55:12 -04001051 auto& v = s.template as<VarDeclaration>();
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04001052 return v.value() && this->visitExpression(*v.value());
John Stiles70b82422020-09-30 10:55:12 -04001053 }
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001054 default:
1055 SkUNREACHABLE;
1056 }
1057}
1058
John Stiles70b82422020-09-30 10:55:12 -04001059template <typename PROG, typename EXPR, typename STMT, typename ELEM>
1060bool TProgramVisitor<PROG, EXPR, STMT, ELEM>::visitProgramElement(ELEM pe) {
1061 switch (pe.kind()) {
Ethan Nicholase6592142020-09-08 10:22:09 -04001062 case ProgramElement::Kind::kEnum:
1063 case ProgramElement::Kind::kExtension:
John Stiles569249b2020-11-03 12:18:22 -05001064 case ProgramElement::Kind::kFunctionPrototype:
John Stilesd39aec02020-12-03 10:42:26 -05001065 case ProgramElement::Kind::kInterfaceBlock:
Ethan Nicholase6592142020-09-08 10:22:09 -04001066 case ProgramElement::Kind::kModifiers:
1067 case ProgramElement::Kind::kSection:
John Stilesdc75a972020-11-25 16:24:55 -05001068 case ProgramElement::Kind::kStructDefinition:
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001069 // Leaf program elements just return false by default
1070 return false;
John Stiles70b82422020-09-30 10:55:12 -04001071
Ethan Nicholase6592142020-09-08 10:22:09 -04001072 case ProgramElement::Kind::kFunction:
Ethan Nicholas0a5d0962020-10-14 13:33:18 -04001073 return this->visitStatement(*pe.template as<FunctionDefinition>().body());
John Stiles70b82422020-09-30 10:55:12 -04001074
Brian Osmanc0213602020-10-06 14:43:32 -04001075 case ProgramElement::Kind::kGlobalVar:
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04001076 if (this->visitStatement(*pe.template as<GlobalVarDeclaration>().declaration())) {
Brian Osmanc0213602020-10-06 14:43:32 -04001077 return true;
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001078 }
1079 return false;
John Stiles70b82422020-09-30 10:55:12 -04001080
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001081 default:
1082 SkUNREACHABLE;
1083 }
1084}
1085
John Stiles70b82422020-09-30 10:55:12 -04001086template class TProgramVisitor<const Program&, const Expression&,
1087 const Statement&, const ProgramElement&>;
1088template class TProgramVisitor<Program&, Expression&, Statement&, ProgramElement&>;
1089
John Stilesa6841be2020-08-06 14:11:56 -04001090} // namespace SkSL