blob: 23384a0d6eaf9387bc01c9d9066c5622f576ac8e [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
Ethan Nicholasdaed2592021-03-04 14:30:25 -050010#include "include/private/SkSLModifiers.h"
Ethan Nicholas24c17722021-03-09 13:10:59 -050011#include "include/private/SkSLProgramElement.h"
Brian Osman1298bc42020-06-30 13:39:35 -040012#include "include/private/SkSLSampleUsage.h"
Ethan Nicholas24c17722021-03-09 13:10:59 -050013#include "include/private/SkSLStatement.h"
Brian Osman00185012021-02-04 16:07:11 -050014#include "src/sksl/SkSLCompiler.h"
John Stilesdce4d3e2020-09-25 14:35:13 -040015#include "src/sksl/SkSLErrorReporter.h"
Michael Ludwig8f3a8362020-06-29 17:27:00 -040016#include "src/sksl/ir/SkSLExpression.h"
17#include "src/sksl/ir/SkSLProgram.h"
Michael Ludwig8f3a8362020-06-29 17:27:00 -040018
19// ProgramElements
20#include "src/sksl/ir/SkSLEnum.h"
21#include "src/sksl/ir/SkSLExtension.h"
22#include "src/sksl/ir/SkSLFunctionDefinition.h"
23#include "src/sksl/ir/SkSLInterfaceBlock.h"
Michael Ludwig8f3a8362020-06-29 17:27:00 -040024#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"
John Stilese1182782021-03-30 22:09:37 -040044#include "src/sksl/ir/SkSLConstructorDiagonalMatrix.h"
John Stiles5abb9e12021-04-06 13:47:19 -040045#include "src/sksl/ir/SkSLConstructorMatrixResize.h"
Michael Ludwig8f3a8362020-06-29 17:27:00 -040046#include "src/sksl/ir/SkSLExternalFunctionCall.h"
Brian Osmanbe0b3b72021-01-06 14:27:35 -050047#include "src/sksl/ir/SkSLExternalFunctionReference.h"
Michael Ludwig8f3a8362020-06-29 17:27:00 -040048#include "src/sksl/ir/SkSLFieldAccess.h"
49#include "src/sksl/ir/SkSLFloatLiteral.h"
50#include "src/sksl/ir/SkSLFunctionCall.h"
51#include "src/sksl/ir/SkSLFunctionReference.h"
52#include "src/sksl/ir/SkSLIndexExpression.h"
John Stiles98c1f822020-09-09 14:18:53 -040053#include "src/sksl/ir/SkSLInlineMarker.h"
Michael Ludwig8f3a8362020-06-29 17:27:00 -040054#include "src/sksl/ir/SkSLIntLiteral.h"
Michael Ludwig8f3a8362020-06-29 17:27:00 -040055#include "src/sksl/ir/SkSLPostfixExpression.h"
56#include "src/sksl/ir/SkSLPrefixExpression.h"
57#include "src/sksl/ir/SkSLSetting.h"
58#include "src/sksl/ir/SkSLSwizzle.h"
59#include "src/sksl/ir/SkSLTernaryExpression.h"
60#include "src/sksl/ir/SkSLTypeReference.h"
61#include "src/sksl/ir/SkSLVariableReference.h"
62
63namespace SkSL {
64
65namespace {
66
67static bool is_sample_call_to_fp(const FunctionCall& fc, const Variable& fp) {
Ethan Nicholas0dec9922020-10-05 15:51:52 -040068 const FunctionDeclaration& f = fc.function();
Ethan Nicholased84b732020-10-08 11:45:44 -040069 return f.isBuiltin() && f.name() == "sample" && fc.arguments().size() >= 1 &&
Ethan Nicholas0dec9922020-10-05 15:51:52 -040070 fc.arguments()[0]->is<VariableReference>() &&
Ethan Nicholas78686922020-10-08 06:46:27 -040071 fc.arguments()[0]->as<VariableReference>().variable() == &fp;
Michael Ludwig8f3a8362020-06-29 17:27:00 -040072}
73
Brian Osman1298bc42020-06-30 13:39:35 -040074// Visitor that determines the merged SampleUsage for a given child 'fp' in the program.
75class MergeSampleUsageVisitor : public ProgramVisitor {
Michael Ludwig8f3a8362020-06-29 17:27:00 -040076public:
Brian Osmancc3d2d22021-04-16 14:53:24 -040077 MergeSampleUsageVisitor(const Context& context, const Variable& fp, bool writesToSampleCoords)
78 : fContext(context), fFP(fp), fWritesToSampleCoords(writesToSampleCoords) {}
Michael Ludwig8f3a8362020-06-29 17:27:00 -040079
Brian Osman1298bc42020-06-30 13:39:35 -040080 SampleUsage visit(const Program& program) {
81 fUsage = SampleUsage(); // reset to none
John Stilesd7ab4502020-09-24 22:41:00 -040082 INHERITED::visit(program);
Brian Osman1298bc42020-06-30 13:39:35 -040083 return fUsage;
Michael Ludwig8f3a8362020-06-29 17:27:00 -040084 }
85
86protected:
John Stiles933abe32020-08-28 11:58:40 -040087 const Context& fContext;
Michael Ludwig8f3a8362020-06-29 17:27:00 -040088 const Variable& fFP;
Brian Osmancc3d2d22021-04-16 14:53:24 -040089 const bool fWritesToSampleCoords;
Brian Osman1298bc42020-06-30 13:39:35 -040090 SampleUsage fUsage;
Michael Ludwig8f3a8362020-06-29 17:27:00 -040091
92 bool visitExpression(const Expression& e) override {
Brian Osman09622682021-04-15 14:43:19 -040093 // Looking for sample(fp, ...)
94 if (e.is<FunctionCall>()) {
John Stiles403a3632020-08-20 12:11:48 -040095 const FunctionCall& fc = e.as<FunctionCall>();
Brian Osman1298bc42020-06-30 13:39:35 -040096 if (is_sample_call_to_fp(fc, fFP)) {
97 // Determine the type of call at this site, and merge it with the accumulated state
Brian Osman09622682021-04-15 14:43:19 -040098 if (fc.arguments().size() >= 2) {
99 const Expression* coords = fc.arguments()[1].get();
100 if (coords->type() == *fContext.fTypes.fFloat2) {
Brian Osmancc3d2d22021-04-16 14:53:24 -0400101 // If the coords are a direct reference to the program's sample-coords,
102 // and those coords are never modified, we can conservatively turn this
103 // into PassThrough sampling. In all other cases, we consider it Explicit.
104 if (!fWritesToSampleCoords && coords->is<VariableReference>() &&
105 coords->as<VariableReference>()
106 .variable()
107 ->modifiers()
108 .fLayout.fBuiltin == SK_MAIN_COORDS_BUILTIN) {
109 fUsage.merge(SampleUsage::PassThrough());
110 } else {
111 fUsage.merge(SampleUsage::Explicit());
112 }
Brian Osman09622682021-04-15 14:43:19 -0400113 } else if (coords->type() == *fContext.fTypes.fFloat3x3) {
114 // Determine the type of matrix for this call site
115 if (coords->isConstantOrUniform()) {
116 if (coords->is<VariableReference>() || coords->isAnyConstructor()) {
117 // FIXME if this is a constant, we should parse the float3x3
118 // constructor and determine if the resulting matrix introduces
119 // perspective.
120 fUsage.merge(SampleUsage::UniformMatrix(coords->description()));
121 } else {
122 // FIXME this is really to workaround a restriction of the
123 // downstream code that relies on the SampleUsage's fExpression to
124 // identify uniform names. Once they are tracked separately, any
125 // uniform expression can work, but right now this avoids issues
126 // from '0.5 * matrix' that is both a constant AND a uniform.
127 fUsage.merge(SampleUsage::VariableMatrix());
128 }
Brian Osman1298bc42020-06-30 13:39:35 -0400129 } else {
Brian Osman1298bc42020-06-30 13:39:35 -0400130 fUsage.merge(SampleUsage::VariableMatrix());
131 }
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400132 } else {
Brian Osman09622682021-04-15 14:43:19 -0400133 // sample(fp, half4 inputColor) -> PassThrough
134 fUsage.merge(SampleUsage::PassThrough());
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400135 }
136 } else {
Brian Osman09622682021-04-15 14:43:19 -0400137 // sample(fp) -> PassThrough
Brian Osman1298bc42020-06-30 13:39:35 -0400138 fUsage.merge(SampleUsage::PassThrough());
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400139 }
Brian Osman1298bc42020-06-30 13:39:35 -0400140 // NOTE: we don't return true here just because we found a sample call. We need to
Brian Osman09622682021-04-15 14:43:19 -0400141 // process the entire program and merge across all encountered calls.
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400142 }
143 }
144
John Stilesd7ab4502020-09-24 22:41:00 -0400145 return INHERITED::visitExpression(e);
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400146 }
147
John Stiles7571f9e2020-09-02 22:42:33 -0400148 using INHERITED = ProgramVisitor;
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400149};
150
Brian Osman92aac1e2020-08-05 16:48:58 -0400151// Visitor that searches through the program for references to a particular builtin variable
152class BuiltinVariableVisitor : public ProgramVisitor {
153public:
154 BuiltinVariableVisitor(int builtin) : fBuiltin(builtin) {}
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400155
156 bool visitExpression(const Expression& e) override {
Brian Osman79457ef2020-09-24 15:01:27 -0400157 if (e.is<VariableReference>()) {
John Stiles403a3632020-08-20 12:11:48 -0400158 const VariableReference& var = e.as<VariableReference>();
Ethan Nicholas78686922020-10-08 06:46:27 -0400159 return var.variable()->modifiers().fLayout.fBuiltin == fBuiltin;
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400160 }
John Stilesd7ab4502020-09-24 22:41:00 -0400161 return INHERITED::visitExpression(e);
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400162 }
163
Brian Osman92aac1e2020-08-05 16:48:58 -0400164 int fBuiltin;
165
John Stiles7571f9e2020-09-02 22:42:33 -0400166 using INHERITED = ProgramVisitor;
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400167};
168
Ethan Nicholas6e0fa402020-08-20 14:08:23 -0400169// Visitor that counts the number of nodes visited
170class NodeCountVisitor : public ProgramVisitor {
171public:
John Stiles2c1e4922020-10-01 09:14:14 -0400172 NodeCountVisitor(int limit) : fLimit(limit) {}
173
Ethan Nicholas6e0fa402020-08-20 14:08:23 -0400174 int visit(const Statement& s) {
Ethan Nicholas6e0fa402020-08-20 14:08:23 -0400175 this->visitStatement(s);
176 return fCount;
177 }
178
179 bool visitExpression(const Expression& e) override {
180 ++fCount;
John Stiles9b9415e2020-11-23 14:48:06 -0500181 return (fCount >= fLimit) || INHERITED::visitExpression(e);
Ethan Nicholas6e0fa402020-08-20 14:08:23 -0400182 }
183
184 bool visitProgramElement(const ProgramElement& p) override {
185 ++fCount;
John Stiles9b9415e2020-11-23 14:48:06 -0500186 return (fCount >= fLimit) || INHERITED::visitProgramElement(p);
Ethan Nicholas6e0fa402020-08-20 14:08:23 -0400187 }
188
189 bool visitStatement(const Statement& s) override {
190 ++fCount;
John Stiles9b9415e2020-11-23 14:48:06 -0500191 return (fCount >= fLimit) || INHERITED::visitStatement(s);
Ethan Nicholas6e0fa402020-08-20 14:08:23 -0400192 }
193
194private:
John Stiles2c1e4922020-10-01 09:14:14 -0400195 int fCount = 0;
196 int fLimit;
Ethan Nicholas6e0fa402020-08-20 14:08:23 -0400197
John Stiles7571f9e2020-09-02 22:42:33 -0400198 using INHERITED = ProgramVisitor;
Ethan Nicholas6e0fa402020-08-20 14:08:23 -0400199};
200
Brian Osman010ce6a2020-10-19 16:34:10 -0400201class ProgramUsageVisitor : public ProgramVisitor {
Brian Osman2e25ff42020-10-15 10:32:04 -0400202public:
Brian Osman010ce6a2020-10-19 16:34:10 -0400203 ProgramUsageVisitor(ProgramUsage* usage, int delta) : fUsage(usage), fDelta(delta) {}
204
John Stiles39465b82021-03-18 09:19:55 -0400205 bool visitProgramElement(const ProgramElement& pe) override {
206 if (pe.is<FunctionDefinition>()) {
207 for (const Variable* param : pe.as<FunctionDefinition>().declaration().parameters()) {
208 // Ensure function-parameter variables exist in the variable usage map. They aren't
209 // otherwise declared, but ProgramUsage::get() should be able to find them, even if
210 // they are unread and unwritten.
211 fUsage->fVariableCounts[param];
212 }
John Stiles8e2a84b2021-04-19 09:35:38 -0400213 } else if (pe.is<InterfaceBlock>()) {
214 // Ensure interface-block variables exist in the variable usage map.
215 fUsage->fVariableCounts[&pe.as<InterfaceBlock>().variable()];
John Stiles39465b82021-03-18 09:19:55 -0400216 }
217 return INHERITED::visitProgramElement(pe);
218 }
219
John Stiles04a8a542021-03-10 19:03:26 -0500220 bool visitStatement(const Statement& s) override {
221 if (s.is<VarDeclaration>()) {
222 // Add all declared variables to the usage map (even if never otherwise accessed).
223 const VarDeclaration& vd = s.as<VarDeclaration>();
224 ProgramUsage::VariableCounts& counts = fUsage->fVariableCounts[&vd.var()];
225 counts.fDeclared += fDelta;
226 SkASSERT(counts.fDeclared >= 0);
227 if (vd.value()) {
228 // The initial-value expression, when present, counts as a write.
229 counts.fWrite += fDelta;
230 }
231 }
232 return INHERITED::visitStatement(s);
233 }
234
Brian Osman2e25ff42020-10-15 10:32:04 -0400235 bool visitExpression(const Expression& e) override {
236 if (e.is<FunctionCall>()) {
237 const FunctionDeclaration* f = &e.as<FunctionCall>().function();
Brian Osman010ce6a2020-10-19 16:34:10 -0400238 fUsage->fCallCounts[f] += fDelta;
239 SkASSERT(fUsage->fCallCounts[f] >= 0);
240 } else if (e.is<VariableReference>()) {
241 const VariableReference& ref = e.as<VariableReference>();
242 ProgramUsage::VariableCounts& counts = fUsage->fVariableCounts[ref.variable()];
243 switch (ref.refKind()) {
244 case VariableRefKind::kRead:
245 counts.fRead += fDelta;
246 break;
247 case VariableRefKind::kWrite:
248 counts.fWrite += fDelta;
249 break;
250 case VariableRefKind::kReadWrite:
251 case VariableRefKind::kPointer:
252 counts.fRead += fDelta;
253 counts.fWrite += fDelta;
254 break;
255 }
256 SkASSERT(counts.fRead >= 0 && counts.fWrite >= 0);
Brian Osman2e25ff42020-10-15 10:32:04 -0400257 }
258 return INHERITED::visitExpression(e);
259 }
260
Brian Osman010ce6a2020-10-19 16:34:10 -0400261 using ProgramVisitor::visitProgramElement;
262 using ProgramVisitor::visitStatement;
263
264 ProgramUsage* fUsage;
265 int fDelta;
Brian Osman2e25ff42020-10-15 10:32:04 -0400266 using INHERITED = ProgramVisitor;
267};
268
Ethan Nicholas765d2fe2020-08-26 08:29:55 -0400269class VariableWriteVisitor : public ProgramVisitor {
270public:
271 VariableWriteVisitor(const Variable* var)
272 : fVar(var) {}
273
274 bool visit(const Statement& s) {
275 return this->visitStatement(s);
276 }
277
278 bool visitExpression(const Expression& e) override {
Brian Osman79457ef2020-09-24 15:01:27 -0400279 if (e.is<VariableReference>()) {
Ethan Nicholas765d2fe2020-08-26 08:29:55 -0400280 const VariableReference& ref = e.as<VariableReference>();
Ethan Nicholas453f67f2020-10-09 10:43:45 -0400281 if (ref.variable() == fVar &&
282 (ref.refKind() == VariableReference::RefKind::kWrite ||
283 ref.refKind() == VariableReference::RefKind::kReadWrite ||
284 ref.refKind() == VariableReference::RefKind::kPointer)) {
Ethan Nicholas765d2fe2020-08-26 08:29:55 -0400285 return true;
286 }
287 }
John Stilesd7ab4502020-09-24 22:41:00 -0400288 return INHERITED::visitExpression(e);
Ethan Nicholas765d2fe2020-08-26 08:29:55 -0400289 }
290
291private:
292 const Variable* fVar;
293
John Stiles7571f9e2020-09-02 22:42:33 -0400294 using INHERITED = ProgramVisitor;
Ethan Nicholas765d2fe2020-08-26 08:29:55 -0400295};
296
John Stilesa976da72020-09-25 23:06:26 -0400297// If a caller doesn't care about errors, we can use this trivial reporter that just counts up.
298class TrivialErrorReporter : public ErrorReporter {
299public:
300 void error(int offset, String) override { ++fErrorCount; }
301 int errorCount() override { return fErrorCount; }
John Stiles8d3642e2021-01-22 09:50:04 -0500302 void setErrorCount(int c) override { fErrorCount = c; }
John Stilesa976da72020-09-25 23:06:26 -0400303
304private:
305 int fErrorCount = 0;
306};
307
John Stilesdce4d3e2020-09-25 14:35:13 -0400308// This isn't actually using ProgramVisitor, because it only considers a subset of the fields for
309// any given expression kind. For instance, when indexing an array (e.g. `x[1]`), we only want to
310// know if the base (`x`) is assignable; the index expression (`1`) doesn't need to be.
311class IsAssignableVisitor {
312public:
John Stilesb21fac22020-12-04 15:36:49 -0500313 IsAssignableVisitor(ErrorReporter* errors) : fErrors(errors) {}
John Stilesdce4d3e2020-09-25 14:35:13 -0400314
John Stilesb21fac22020-12-04 15:36:49 -0500315 bool visit(Expression& expr, Analysis::AssignmentInfo* info) {
Ethan Nicholas67a0a8a2021-01-13 12:36:02 -0500316 int oldErrorCount = fErrors->errorCount();
John Stilesdce4d3e2020-09-25 14:35:13 -0400317 this->visitExpression(expr);
John Stilesb21fac22020-12-04 15:36:49 -0500318 if (info) {
319 info->fAssignedVar = fAssignedVar;
John Stilesb21fac22020-12-04 15:36:49 -0500320 }
Ethan Nicholas67a0a8a2021-01-13 12:36:02 -0500321 return fErrors->errorCount() == oldErrorCount;
John Stilesdce4d3e2020-09-25 14:35:13 -0400322 }
323
324 void visitExpression(Expression& expr) {
325 switch (expr.kind()) {
326 case Expression::Kind::kVariableReference: {
327 VariableReference& varRef = expr.as<VariableReference>();
Ethan Nicholas78686922020-10-08 06:46:27 -0400328 const Variable* var = varRef.variable();
Ethan Nicholas041fd0a2020-10-07 16:42:04 -0400329 if (var->modifiers().fFlags & (Modifiers::kConst_Flag | Modifiers::kUniform_Flag |
330 Modifiers::kVarying_Flag)) {
John Stilesa976da72020-09-25 23:06:26 -0400331 fErrors->error(expr.fOffset,
Ethan Nicholase2c49992020-10-05 11:49:11 -0400332 "cannot modify immutable variable '" + var->name() + "'");
John Stilesb21fac22020-12-04 15:36:49 -0500333 } else {
334 SkASSERT(fAssignedVar == nullptr);
335 fAssignedVar = &varRef;
John Stilesdce4d3e2020-09-25 14:35:13 -0400336 }
337 break;
338 }
339 case Expression::Kind::kFieldAccess:
Ethan Nicholas7a95b202020-10-09 11:55:40 -0400340 this->visitExpression(*expr.as<FieldAccess>().base());
John Stilesdce4d3e2020-09-25 14:35:13 -0400341 break;
342
343 case Expression::Kind::kSwizzle: {
344 const Swizzle& swizzle = expr.as<Swizzle>();
345 this->checkSwizzleWrite(swizzle);
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400346 this->visitExpression(*swizzle.base());
John Stilesdce4d3e2020-09-25 14:35:13 -0400347 break;
348 }
John Stiles47c0a742021-02-09 09:30:35 -0500349 case Expression::Kind::kIndex:
350 this->visitExpression(*expr.as<IndexExpression>().base());
John Stilesdce4d3e2020-09-25 14:35:13 -0400351 break;
John Stiles47c0a742021-02-09 09:30:35 -0500352
John Stilesdce4d3e2020-09-25 14:35:13 -0400353 default:
John Stilesa976da72020-09-25 23:06:26 -0400354 fErrors->error(expr.fOffset, "cannot assign to this expression");
John Stilesdce4d3e2020-09-25 14:35:13 -0400355 break;
356 }
357 }
358
359private:
360 void checkSwizzleWrite(const Swizzle& swizzle) {
361 int bits = 0;
John Stiles6e88e042021-02-19 14:09:38 -0500362 for (int8_t idx : swizzle.components()) {
363 SkASSERT(idx >= SwizzleComponent::X && idx <= SwizzleComponent::W);
John Stilesdce4d3e2020-09-25 14:35:13 -0400364 int bit = 1 << idx;
365 if (bits & bit) {
John Stilesa976da72020-09-25 23:06:26 -0400366 fErrors->error(swizzle.fOffset,
367 "cannot write to the same swizzle field more than once");
John Stilesdce4d3e2020-09-25 14:35:13 -0400368 break;
369 }
370 bits |= bit;
371 }
372 }
373
John Stilesa976da72020-09-25 23:06:26 -0400374 ErrorReporter* fErrors;
John Stilesb21fac22020-12-04 15:36:49 -0500375 VariableReference* fAssignedVar = nullptr;
John Stilesdce4d3e2020-09-25 14:35:13 -0400376
377 using INHERITED = ProgramVisitor;
378};
379
John Stiles642cde22021-02-23 14:57:01 -0500380class SwitchCaseContainsExit : public ProgramVisitor {
381public:
382 SwitchCaseContainsExit(bool conditionalExits) : fConditionalExits(conditionalExits) {}
383
384 bool visitStatement(const Statement& stmt) override {
385 switch (stmt.kind()) {
386 case Statement::Kind::kBlock:
John Stilesa0e56e32021-03-03 13:14:37 -0500387 case Statement::Kind::kSwitchCase:
John Stiles642cde22021-02-23 14:57:01 -0500388 return INHERITED::visitStatement(stmt);
389
390 case Statement::Kind::kReturn:
391 // Returns are an early exit regardless of the surrounding control structures.
392 return fConditionalExits ? fInConditional : !fInConditional;
393
394 case Statement::Kind::kContinue:
395 // Continues are an early exit from switches, but not loops.
396 return !fInLoop &&
397 (fConditionalExits ? fInConditional : !fInConditional);
398
399 case Statement::Kind::kBreak:
400 // Breaks cannot escape from switches or loops.
401 return !fInLoop && !fInSwitch &&
402 (fConditionalExits ? fInConditional : !fInConditional);
403
404 case Statement::Kind::kIf: {
405 ++fInConditional;
406 bool result = INHERITED::visitStatement(stmt);
407 --fInConditional;
408 return result;
409 }
410
411 case Statement::Kind::kFor:
412 case Statement::Kind::kDo: {
413 // Loops are treated as conditionals because a loop could potentially execute zero
414 // times. We don't have a straightforward way to determine that a loop definitely
415 // executes at least once.
416 ++fInConditional;
417 ++fInLoop;
418 bool result = INHERITED::visitStatement(stmt);
419 --fInLoop;
420 --fInConditional;
421 return result;
422 }
423
424 case Statement::Kind::kSwitch: {
425 ++fInSwitch;
426 bool result = INHERITED::visitStatement(stmt);
427 --fInSwitch;
428 return result;
429 }
430
431 default:
432 return false;
433 }
434 }
435
436 bool fConditionalExits = false;
437 int fInConditional = 0;
438 int fInLoop = 0;
439 int fInSwitch = 0;
440 using INHERITED = ProgramVisitor;
441};
442
John Stilesb3dcbb12021-03-04 16:00:20 -0500443class ReturnsOnAllPathsVisitor : public ProgramVisitor {
444public:
445 bool visitExpression(const Expression& expr) override {
446 // We can avoid processing expressions entirely.
447 return false;
448 }
449
450 bool visitStatement(const Statement& stmt) override {
451 switch (stmt.kind()) {
452 // Returns, breaks, or continues will stop the scan, so only one of these should ever be
453 // true.
454 case Statement::Kind::kReturn:
455 fFoundReturn = true;
456 return true;
457
458 case Statement::Kind::kBreak:
459 fFoundBreak = true;
460 return true;
461
462 case Statement::Kind::kContinue:
463 fFoundContinue = true;
464 return true;
465
466 case Statement::Kind::kIf: {
467 const IfStatement& i = stmt.as<IfStatement>();
468 ReturnsOnAllPathsVisitor trueVisitor;
469 ReturnsOnAllPathsVisitor falseVisitor;
470 trueVisitor.visitStatement(*i.ifTrue());
471 if (i.ifFalse()) {
472 falseVisitor.visitStatement(*i.ifFalse());
473 }
474 // If either branch leads to a break or continue, we report the entire if as
475 // containing a break or continue, since we don't know which side will be reached.
476 fFoundBreak = (trueVisitor.fFoundBreak || falseVisitor.fFoundBreak);
477 fFoundContinue = (trueVisitor.fFoundContinue || falseVisitor.fFoundContinue);
478 // On the other hand, we only want to report returns that definitely happen, so we
479 // require those to be found on both sides.
480 fFoundReturn = (trueVisitor.fFoundReturn && falseVisitor.fFoundReturn);
481 return fFoundBreak || fFoundContinue || fFoundReturn;
482 }
483 case Statement::Kind::kFor: {
484 const ForStatement& f = stmt.as<ForStatement>();
485 // We assume a for/while loop runs for at least one iteration; this isn't strictly
486 // guaranteed, but it's better to be slightly over-permissive here than to fail on
487 // reasonable code.
488 ReturnsOnAllPathsVisitor forVisitor;
489 forVisitor.visitStatement(*f.statement());
490 // A for loop that contains a break or continue is safe; it won't exit the entire
491 // function, just the loop. So we disregard those signals.
492 fFoundReturn = forVisitor.fFoundReturn;
493 return fFoundReturn;
494 }
495 case Statement::Kind::kDo: {
496 const DoStatement& d = stmt.as<DoStatement>();
497 // Do-while blocks are always entered at least once.
498 ReturnsOnAllPathsVisitor doVisitor;
499 doVisitor.visitStatement(*d.statement());
500 // A do-while loop that contains a break or continue is safe; it won't exit the
501 // entire function, just the loop. So we disregard those signals.
502 fFoundReturn = doVisitor.fFoundReturn;
503 return fFoundReturn;
504 }
505 case Statement::Kind::kBlock:
506 // Blocks are definitely entered and don't imply any additional control flow.
507 // If the block contains a break, continue or return, we want to keep that.
508 return INHERITED::visitStatement(stmt);
509
510 case Statement::Kind::kSwitch: {
511 // Switches are the most complex control flow we need to deal with; fortunately we
512 // already have good primitives for dissecting them. We need to verify that:
513 // - a default case exists, so that every possible input value is covered
514 // - every switch-case either (a) returns unconditionally, or
515 // (b) falls through to another case that does
516 const SwitchStatement& s = stmt.as<SwitchStatement>();
517 bool foundDefault = false;
518 bool fellThrough = false;
John Stilesb23a64b2021-03-11 08:27:59 -0500519 for (const std::unique_ptr<Statement>& stmt : s.cases()) {
John Stilesb3dcbb12021-03-04 16:00:20 -0500520 // The default case is indicated by a null value. A switch without a default
521 // case cannot definitively return, as its value might not be in the cases list.
John Stilesb23a64b2021-03-11 08:27:59 -0500522 const SwitchCase& sc = stmt->as<SwitchCase>();
523 if (!sc.value()) {
John Stilesb3dcbb12021-03-04 16:00:20 -0500524 foundDefault = true;
525 }
526 // Scan this switch-case for any exit (break, continue or return).
527 ReturnsOnAllPathsVisitor caseVisitor;
John Stilesb23a64b2021-03-11 08:27:59 -0500528 caseVisitor.visitStatement(sc);
John Stilesb3dcbb12021-03-04 16:00:20 -0500529
530 // If we found a break or continue, whether conditional or not, this switch case
531 // can't be called an unconditional return. Switches absorb breaks but not
532 // continues.
533 if (caseVisitor.fFoundContinue) {
534 fFoundContinue = true;
535 return false;
536 }
537 if (caseVisitor.fFoundBreak) {
538 return false;
539 }
540 // We just confirmed that there weren't any breaks or continues. If we didn't
541 // find an unconditional return either, the switch is considered fallen-through.
542 // (There might be a conditional return, but that doesn't count.)
543 fellThrough = !caseVisitor.fFoundReturn;
544 }
545
546 // If we didn't find a default case, or the very last case fell through, this switch
547 // doesn't meet our criteria.
548 if (fellThrough || !foundDefault) {
549 return false;
550 }
551
552 // We scanned the entire switch, found a default case, and every section either fell
553 // through or contained an unconditional return.
554 fFoundReturn = true;
555 return true;
556 }
557
558 case Statement::Kind::kSwitchCase:
559 // Recurse into the switch-case.
560 return INHERITED::visitStatement(stmt);
561
562 case Statement::Kind::kDiscard:
563 case Statement::Kind::kExpression:
564 case Statement::Kind::kInlineMarker:
565 case Statement::Kind::kNop:
566 case Statement::Kind::kVarDeclaration:
567 // None of these statements could contain a return.
568 break;
569 }
570
571 return false;
572 }
573
574 bool fFoundReturn = false;
575 bool fFoundBreak = false;
576 bool fFoundContinue = false;
577
578 using INHERITED = ProgramVisitor;
579};
580
John Stilesa6841be2020-08-06 14:11:56 -0400581} // namespace
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400582
583////////////////////////////////////////////////////////////////////////////////
584// Analysis
585
Brian Osmancc3d2d22021-04-16 14:53:24 -0400586SampleUsage Analysis::GetSampleUsage(const Program& program,
587 const Variable& fp,
588 bool writesToSampleCoords) {
589 MergeSampleUsageVisitor visitor(*program.fContext, fp, writesToSampleCoords);
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400590 return visitor.visit(program);
591}
592
Brian Osman92aac1e2020-08-05 16:48:58 -0400593bool Analysis::ReferencesBuiltin(const Program& program, int builtin) {
594 BuiltinVariableVisitor visitor(builtin);
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400595 return visitor.visit(program);
596}
597
Brian Osman92aac1e2020-08-05 16:48:58 -0400598bool Analysis::ReferencesSampleCoords(const Program& program) {
599 return Analysis::ReferencesBuiltin(program, SK_MAIN_COORDS_BUILTIN);
600}
601
602bool Analysis::ReferencesFragCoords(const Program& program) {
603 return Analysis::ReferencesBuiltin(program, SK_FRAGCOORD_BUILTIN);
604}
605
John Stiles9b9415e2020-11-23 14:48:06 -0500606int Analysis::NodeCountUpToLimit(const FunctionDefinition& function, int limit) {
607 return NodeCountVisitor{limit}.visit(*function.body());
Ethan Nicholas6e0fa402020-08-20 14:08:23 -0400608}
609
John Stiles642cde22021-02-23 14:57:01 -0500610bool Analysis::SwitchCaseContainsUnconditionalExit(Statement& stmt) {
611 return SwitchCaseContainsExit{/*conditionalExits=*/false}.visitStatement(stmt);
612}
613
614bool Analysis::SwitchCaseContainsConditionalExit(Statement& stmt) {
615 return SwitchCaseContainsExit{/*conditionalExits=*/true}.visitStatement(stmt);
616}
617
Brian Osman010ce6a2020-10-19 16:34:10 -0400618std::unique_ptr<ProgramUsage> Analysis::GetUsage(const Program& program) {
619 auto usage = std::make_unique<ProgramUsage>();
620 ProgramUsageVisitor addRefs(usage.get(), /*delta=*/+1);
621 addRefs.visit(program);
622 return usage;
623}
624
Brian Osman0006ad02020-11-18 15:38:39 -0500625std::unique_ptr<ProgramUsage> Analysis::GetUsage(const LoadedModule& module) {
626 auto usage = std::make_unique<ProgramUsage>();
627 ProgramUsageVisitor addRefs(usage.get(), /*delta=*/+1);
628 for (const auto& element : module.fElements) {
629 addRefs.visitProgramElement(*element);
630 }
631 return usage;
632}
633
Brian Osman010ce6a2020-10-19 16:34:10 -0400634ProgramUsage::VariableCounts ProgramUsage::get(const Variable& v) const {
John Stiles04a8a542021-03-10 19:03:26 -0500635 const VariableCounts* counts = fVariableCounts.find(&v);
636 SkASSERT(counts);
637 return *counts;
Brian Osman010ce6a2020-10-19 16:34:10 -0400638}
639
640bool ProgramUsage::isDead(const Variable& v) const {
641 const Modifiers& modifiers = v.modifiers();
642 VariableCounts counts = this->get(v);
643 if ((v.storage() != Variable::Storage::kLocal && counts.fRead) ||
644 (modifiers.fFlags & (Modifiers::kIn_Flag | Modifiers::kOut_Flag | Modifiers::kUniform_Flag |
645 Modifiers::kVarying_Flag))) {
646 return false;
647 }
John Stilesf10eff32021-03-16 10:57:55 -0400648 // Consider the variable dead if it's never read and never written (besides the initial-value).
649 return !counts.fRead && (counts.fWrite <= (v.initialValue() ? 1 : 0));
Brian Osman010ce6a2020-10-19 16:34:10 -0400650}
651
652int ProgramUsage::get(const FunctionDeclaration& f) const {
653 const int* count = fCallCounts.find(&f);
654 return count ? *count : 0;
655}
656
657void ProgramUsage::replace(const Expression* oldExpr, const Expression* newExpr) {
658 if (oldExpr) {
659 ProgramUsageVisitor subRefs(this, /*delta=*/-1);
660 subRefs.visitExpression(*oldExpr);
661 }
662 if (newExpr) {
663 ProgramUsageVisitor addRefs(this, /*delta=*/+1);
664 addRefs.visitExpression(*newExpr);
665 }
666}
667
668void ProgramUsage::add(const Statement* stmt) {
669 ProgramUsageVisitor addRefs(this, /*delta=*/+1);
670 addRefs.visitStatement(*stmt);
671}
672
673void ProgramUsage::remove(const Expression* expr) {
674 ProgramUsageVisitor subRefs(this, /*delta=*/-1);
675 subRefs.visitExpression(*expr);
676}
677
678void ProgramUsage::remove(const Statement* stmt) {
679 ProgramUsageVisitor subRefs(this, /*delta=*/-1);
680 subRefs.visitStatement(*stmt);
681}
682
683void ProgramUsage::remove(const ProgramElement& element) {
684 ProgramUsageVisitor subRefs(this, /*delta=*/-1);
685 subRefs.visitProgramElement(element);
Brian Osman2e25ff42020-10-15 10:32:04 -0400686}
687
Ethan Nicholas765d2fe2020-08-26 08:29:55 -0400688bool Analysis::StatementWritesToVariable(const Statement& stmt, const Variable& var) {
689 return VariableWriteVisitor(&var).visit(stmt);
690}
691
John Stilesb21fac22020-12-04 15:36:49 -0500692bool Analysis::IsAssignable(Expression& expr, AssignmentInfo* info, ErrorReporter* errors) {
John Stilesa976da72020-09-25 23:06:26 -0400693 TrivialErrorReporter trivialErrors;
John Stilesb21fac22020-12-04 15:36:49 -0500694 return IsAssignableVisitor{errors ? errors : &trivialErrors}.visit(expr, info);
John Stilesdce4d3e2020-09-25 14:35:13 -0400695}
696
John Stiles47c0a742021-02-09 09:30:35 -0500697void Analysis::UpdateRefKind(Expression* expr, VariableRefKind refKind) {
698 class RefKindWriter : public ProgramWriter {
699 public:
700 RefKindWriter(VariableReference::RefKind refKind) : fRefKind(refKind) {}
701
702 bool visitExpression(Expression& expr) override {
703 if (expr.is<VariableReference>()) {
704 expr.as<VariableReference>().setRefKind(fRefKind);
705 }
706 return INHERITED::visitExpression(expr);
707 }
708
709 private:
710 VariableReference::RefKind fRefKind;
711
712 using INHERITED = ProgramWriter;
713 };
714
715 RefKindWriter{refKind}.visitExpression(*expr);
716}
717
John Stiles516704b2021-02-26 15:01:57 -0500718bool Analysis::MakeAssignmentExpr(Expression* expr,
719 VariableReference::RefKind kind,
720 ErrorReporter* errors) {
721 Analysis::AssignmentInfo info;
722 if (!Analysis::IsAssignable(*expr, &info, errors)) {
723 return false;
724 }
725 if (!info.fAssignedVar) {
726 errors->error(expr->fOffset, "can't assign to expression '" + expr->description() + "'");
727 return false;
728 }
729 info.fAssignedVar->setRefKind(kind);
730 return true;
731}
732
John Stilesc30fbca2020-11-19 16:25:49 -0500733bool Analysis::IsTrivialExpression(const Expression& expr) {
734 return expr.is<IntLiteral>() ||
735 expr.is<FloatLiteral>() ||
736 expr.is<BoolLiteral>() ||
737 expr.is<VariableReference>() ||
738 (expr.is<Swizzle>() &&
739 IsTrivialExpression(*expr.as<Swizzle>().base())) ||
740 (expr.is<FieldAccess>() &&
741 IsTrivialExpression(*expr.as<FieldAccess>().base())) ||
John Stiles2938eea2021-04-01 18:58:25 -0400742 (expr.isAnyConstructor() &&
743 expr.asAnyConstructor().argumentSpan().size() == 1 &&
744 IsTrivialExpression(*expr.asAnyConstructor().argumentSpan().front())) ||
745 (expr.isAnyConstructor() &&
John Stilesc30fbca2020-11-19 16:25:49 -0500746 expr.isConstantOrUniform()) ||
747 (expr.is<IndexExpression>() &&
748 expr.as<IndexExpression>().index()->is<IntLiteral>() &&
749 IsTrivialExpression(*expr.as<IndexExpression>().base()));
750}
751
John Stiles5676c572021-03-08 17:10:52 -0500752bool Analysis::IsSameExpressionTree(const Expression& left, const Expression& right) {
John Stiles95d0bad2021-03-01 17:02:28 -0500753 if (left.kind() != right.kind() || left.type() != right.type()) {
754 return false;
755 }
756
John Stiles5676c572021-03-08 17:10:52 -0500757 // This isn't a fully exhaustive list of expressions by any stretch of the imagination; for
758 // instance, `x[y+1] = x[y+1]` isn't detected because we don't look at BinaryExpressions.
759 // Since this is intended to be used for optimization purposes, handling the common cases is
760 // sufficient.
John Stiles95d0bad2021-03-01 17:02:28 -0500761 switch (left.kind()) {
762 case Expression::Kind::kIntLiteral:
763 return left.as<IntLiteral>().value() == right.as<IntLiteral>().value();
764
John Stiles5676c572021-03-08 17:10:52 -0500765 case Expression::Kind::kFloatLiteral:
766 return left.as<FloatLiteral>().value() == right.as<FloatLiteral>().value();
767
768 case Expression::Kind::kBoolLiteral:
769 return left.as<BoolLiteral>().value() == right.as<BoolLiteral>().value();
770
John Stiles7384b372021-04-01 13:48:15 -0400771 case Expression::Kind::kConstructorArray:
John Stiles8cad6372021-04-07 12:31:13 -0400772 case Expression::Kind::kConstructorCompound:
773 case Expression::Kind::kConstructorCompoundCast:
John Stiles2938eea2021-04-01 18:58:25 -0400774 case Expression::Kind::kConstructorDiagonalMatrix:
John Stiles5abb9e12021-04-06 13:47:19 -0400775 case Expression::Kind::kConstructorMatrixResize:
John Stilesfd7252f2021-04-04 22:24:40 -0400776 case Expression::Kind::kConstructorScalarCast:
John Stilesd47330f2021-04-08 23:25:52 -0400777 case Expression::Kind::kConstructorStruct:
John Stiles268a73f2021-04-07 12:30:22 -0400778 case Expression::Kind::kConstructorSplat: {
John Stilesfd7252f2021-04-04 22:24:40 -0400779 if (left.kind() != right.kind()) {
780 return false;
781 }
John Stiles7384b372021-04-01 13:48:15 -0400782 const AnyConstructor& leftCtor = left.asAnyConstructor();
783 const AnyConstructor& rightCtor = right.asAnyConstructor();
784 const auto leftSpan = leftCtor.argumentSpan();
785 const auto rightSpan = rightCtor.argumentSpan();
786 if (leftSpan.size() != rightSpan.size()) {
John Stiles5676c572021-03-08 17:10:52 -0500787 return false;
788 }
John Stiles7384b372021-04-01 13:48:15 -0400789 for (size_t index = 0; index < leftSpan.size(); ++index) {
790 if (!IsSameExpressionTree(*leftSpan[index], *rightSpan[index])) {
John Stiles5676c572021-03-08 17:10:52 -0500791 return false;
792 }
793 }
794 return true;
795 }
John Stiles95d0bad2021-03-01 17:02:28 -0500796 case Expression::Kind::kFieldAccess:
797 return left.as<FieldAccess>().fieldIndex() == right.as<FieldAccess>().fieldIndex() &&
John Stiles5676c572021-03-08 17:10:52 -0500798 IsSameExpressionTree(*left.as<FieldAccess>().base(),
799 *right.as<FieldAccess>().base());
John Stiles95d0bad2021-03-01 17:02:28 -0500800
801 case Expression::Kind::kIndex:
John Stiles5676c572021-03-08 17:10:52 -0500802 return IsSameExpressionTree(*left.as<IndexExpression>().index(),
803 *right.as<IndexExpression>().index()) &&
804 IsSameExpressionTree(*left.as<IndexExpression>().base(),
805 *right.as<IndexExpression>().base());
John Stiles95d0bad2021-03-01 17:02:28 -0500806
807 case Expression::Kind::kSwizzle:
808 return left.as<Swizzle>().components() == right.as<Swizzle>().components() &&
John Stiles5676c572021-03-08 17:10:52 -0500809 IsSameExpressionTree(*left.as<Swizzle>().base(), *right.as<Swizzle>().base());
John Stiles95d0bad2021-03-01 17:02:28 -0500810
811 case Expression::Kind::kVariableReference:
812 return left.as<VariableReference>().variable() ==
813 right.as<VariableReference>().variable();
814
815 default:
816 return false;
817 }
818}
819
John Stilesd80cef62021-03-29 11:22:43 -0400820static bool get_constant_value(const Expression& expr, double* val) {
John Stiles21a50ec2021-04-06 14:49:36 -0400821 const Expression* valExpr = expr.getConstantSubexpression(0);
822 if (!valExpr) {
John Stilesd80cef62021-03-29 11:22:43 -0400823 return false;
824 }
John Stiles21a50ec2021-04-06 14:49:36 -0400825 if (valExpr->is<IntLiteral>()) {
826 *val = static_cast<double>(valExpr->as<IntLiteral>().value());
827 return true;
John Stilesd80cef62021-03-29 11:22:43 -0400828 }
John Stiles21a50ec2021-04-06 14:49:36 -0400829 if (valExpr->is<FloatLiteral>()) {
830 *val = static_cast<double>(valExpr->as<FloatLiteral>().value());
831 return true;
832 }
833 SkDEBUGFAILF("unexpected constant type (%s)", expr.type().description().c_str());
834 return false;
John Stilesd80cef62021-03-29 11:22:43 -0400835}
836
John Stiles232b4ce2021-03-01 22:14:22 -0500837static const char* invalid_for_ES2(int offset,
838 const Statement* loopInitializer,
839 const Expression* loopTest,
840 const Expression* loopNext,
841 const Statement* loopStatement,
Brian Osman77ba8102021-01-12 17:15:30 -0500842 Analysis::UnrollableLoopInfo& loopInfo) {
Brian Osman77ba8102021-01-12 17:15:30 -0500843 //
844 // init_declaration has the form: type_specifier identifier = constant_expression
845 //
John Stiles232b4ce2021-03-01 22:14:22 -0500846 if (!loopInitializer) {
Brian Osman77ba8102021-01-12 17:15:30 -0500847 return "missing init declaration";
848 }
John Stiles232b4ce2021-03-01 22:14:22 -0500849 if (!loopInitializer->is<VarDeclaration>()) {
Brian Osman77ba8102021-01-12 17:15:30 -0500850 return "invalid init declaration";
851 }
John Stiles232b4ce2021-03-01 22:14:22 -0500852 const VarDeclaration& initDecl = loopInitializer->as<VarDeclaration>();
Brian Osman6c7910e2021-01-14 09:50:52 -0500853 if (!initDecl.baseType().isNumber()) {
Brian Osman77ba8102021-01-12 17:15:30 -0500854 return "invalid type for loop index";
855 }
856 if (initDecl.arraySize() != 0) {
857 return "invalid type for loop index";
858 }
859 if (!initDecl.value()) {
860 return "missing loop index initializer";
861 }
John Stilesd80cef62021-03-29 11:22:43 -0400862 if (!get_constant_value(*initDecl.value(), &loopInfo.fStart)) {
Brian Osman77ba8102021-01-12 17:15:30 -0500863 return "loop index initializer must be a constant expression";
864 }
865
866 loopInfo.fIndex = &initDecl.var();
867
868 auto is_loop_index = [&](const std::unique_ptr<Expression>& expr) {
869 return expr->is<VariableReference>() &&
870 expr->as<VariableReference>().variable() == loopInfo.fIndex;
871 };
872
873 //
874 // condition has the form: loop_index relational_operator constant_expression
875 //
John Stiles232b4ce2021-03-01 22:14:22 -0500876 if (!loopTest) {
Brian Osman77ba8102021-01-12 17:15:30 -0500877 return "missing condition";
878 }
John Stiles232b4ce2021-03-01 22:14:22 -0500879 if (!loopTest->is<BinaryExpression>()) {
Brian Osman77ba8102021-01-12 17:15:30 -0500880 return "invalid condition";
881 }
John Stiles232b4ce2021-03-01 22:14:22 -0500882 const BinaryExpression& cond = loopTest->as<BinaryExpression>();
Brian Osman77ba8102021-01-12 17:15:30 -0500883 if (!is_loop_index(cond.left())) {
884 return "expected loop index on left hand side of condition";
885 }
886 // relational_operator is one of: > >= < <= == or !=
John Stiles45990502021-02-16 10:55:27 -0500887 switch (cond.getOperator().kind()) {
Brian Osman77ba8102021-01-12 17:15:30 -0500888 case Token::Kind::TK_GT:
889 case Token::Kind::TK_GTEQ:
890 case Token::Kind::TK_LT:
891 case Token::Kind::TK_LTEQ:
892 case Token::Kind::TK_EQEQ:
893 case Token::Kind::TK_NEQ:
894 break;
895 default:
896 return "invalid relational operator";
897 }
898 double loopEnd = 0;
John Stilesd80cef62021-03-29 11:22:43 -0400899 if (!get_constant_value(*cond.right(), &loopEnd)) {
Brian Osman77ba8102021-01-12 17:15:30 -0500900 return "loop index must be compared with a constant expression";
901 }
902
903 //
904 // expression has one of the following forms:
905 // loop_index++
906 // loop_index--
907 // loop_index += constant_expression
908 // loop_index -= constant_expression
909 // The spec doesn't mention prefix increment and decrement, but there is some consensus that
910 // it's an oversight, so we allow those as well.
911 //
John Stiles232b4ce2021-03-01 22:14:22 -0500912 if (!loopNext) {
Brian Osman77ba8102021-01-12 17:15:30 -0500913 return "missing loop expression";
914 }
John Stiles232b4ce2021-03-01 22:14:22 -0500915 switch (loopNext->kind()) {
Brian Osman77ba8102021-01-12 17:15:30 -0500916 case Expression::Kind::kBinary: {
John Stiles232b4ce2021-03-01 22:14:22 -0500917 const BinaryExpression& next = loopNext->as<BinaryExpression>();
Brian Osman77ba8102021-01-12 17:15:30 -0500918 if (!is_loop_index(next.left())) {
919 return "expected loop index in loop expression";
920 }
John Stilesd80cef62021-03-29 11:22:43 -0400921 if (!get_constant_value(*next.right(), &loopInfo.fDelta)) {
Brian Osman77ba8102021-01-12 17:15:30 -0500922 return "loop index must be modified by a constant expression";
923 }
John Stiles45990502021-02-16 10:55:27 -0500924 switch (next.getOperator().kind()) {
Brian Osman77ba8102021-01-12 17:15:30 -0500925 case Token::Kind::TK_PLUSEQ: break;
926 case Token::Kind::TK_MINUSEQ: loopInfo.fDelta = -loopInfo.fDelta; break;
927 default:
928 return "invalid operator in loop expression";
929 }
930 } break;
931 case Expression::Kind::kPrefix: {
John Stiles232b4ce2021-03-01 22:14:22 -0500932 const PrefixExpression& next = loopNext->as<PrefixExpression>();
Brian Osman77ba8102021-01-12 17:15:30 -0500933 if (!is_loop_index(next.operand())) {
934 return "expected loop index in loop expression";
935 }
John Stiles45990502021-02-16 10:55:27 -0500936 switch (next.getOperator().kind()) {
Brian Osman77ba8102021-01-12 17:15:30 -0500937 case Token::Kind::TK_PLUSPLUS: loopInfo.fDelta = 1; break;
938 case Token::Kind::TK_MINUSMINUS: loopInfo.fDelta = -1; break;
939 default:
940 return "invalid operator in loop expression";
941 }
942 } break;
943 case Expression::Kind::kPostfix: {
John Stiles232b4ce2021-03-01 22:14:22 -0500944 const PostfixExpression& next = loopNext->as<PostfixExpression>();
Brian Osman77ba8102021-01-12 17:15:30 -0500945 if (!is_loop_index(next.operand())) {
946 return "expected loop index in loop expression";
947 }
John Stiles45990502021-02-16 10:55:27 -0500948 switch (next.getOperator().kind()) {
Brian Osman77ba8102021-01-12 17:15:30 -0500949 case Token::Kind::TK_PLUSPLUS: loopInfo.fDelta = 1; break;
950 case Token::Kind::TK_MINUSMINUS: loopInfo.fDelta = -1; break;
951 default:
952 return "invalid operator in loop expression";
953 }
954 } break;
955 default:
956 return "invalid loop expression";
957 }
958
959 //
960 // Within the body of the loop, the loop index is not statically assigned to, nor is it used as
961 // argument to a function 'out' or 'inout' parameter.
962 //
John Stiles232b4ce2021-03-01 22:14:22 -0500963 if (Analysis::StatementWritesToVariable(*loopStatement, initDecl.var())) {
Brian Osman77ba8102021-01-12 17:15:30 -0500964 return "loop index must not be modified within body of the loop";
965 }
966
967 // Finally, compute the iteration count, based on the bounds, and the termination operator.
968 constexpr int kMaxUnrollableLoopLength = 128;
969 loopInfo.fCount = 0;
970
971 double val = loopInfo.fStart;
972 auto evalCond = [&]() {
John Stiles45990502021-02-16 10:55:27 -0500973 switch (cond.getOperator().kind()) {
Brian Osman77ba8102021-01-12 17:15:30 -0500974 case Token::Kind::TK_GT: return val > loopEnd;
975 case Token::Kind::TK_GTEQ: return val >= loopEnd;
976 case Token::Kind::TK_LT: return val < loopEnd;
977 case Token::Kind::TK_LTEQ: return val <= loopEnd;
978 case Token::Kind::TK_EQEQ: return val == loopEnd;
979 case Token::Kind::TK_NEQ: return val != loopEnd;
980 default: SkUNREACHABLE;
981 }
982 };
983
984 for (loopInfo.fCount = 0; loopInfo.fCount <= kMaxUnrollableLoopLength; ++loopInfo.fCount) {
985 if (!evalCond()) {
986 break;
987 }
988 val += loopInfo.fDelta;
989 }
990
991 if (loopInfo.fCount > kMaxUnrollableLoopLength) {
992 return "loop must guarantee termination in fewer iterations";
993 }
994
995 return nullptr; // All checks pass
996}
997
John Stiles232b4ce2021-03-01 22:14:22 -0500998bool Analysis::ForLoopIsValidForES2(int offset,
999 const Statement* loopInitializer,
1000 const Expression* loopTest,
1001 const Expression* loopNext,
1002 const Statement* loopStatement,
Brian Osman77ba8102021-01-12 17:15:30 -05001003 Analysis::UnrollableLoopInfo* outLoopInfo,
1004 ErrorReporter* errors) {
1005 UnrollableLoopInfo ignored,
1006 *loopInfo = outLoopInfo ? outLoopInfo : &ignored;
John Stiles232b4ce2021-03-01 22:14:22 -05001007 if (const char* msg = invalid_for_ES2(
1008 offset, loopInitializer, loopTest, loopNext, loopStatement, *loopInfo)) {
Brian Osman77ba8102021-01-12 17:15:30 -05001009 if (errors) {
John Stiles232b4ce2021-03-01 22:14:22 -05001010 errors->error(offset, msg);
Brian Osman77ba8102021-01-12 17:15:30 -05001011 }
1012 return false;
1013 }
1014 return true;
1015}
1016
Brian Osman7b361492021-02-25 11:25:30 -05001017// Checks for ES2 constant-expression rules, and (optionally) constant-index-expression rules
1018// (if loopIndices is non-nullptr)
1019class ConstantExpressionVisitor : public ProgramVisitor {
Brian Osmanea485e52021-01-15 13:20:32 -05001020public:
Brian Osman7b361492021-02-25 11:25:30 -05001021 ConstantExpressionVisitor(const std::set<const Variable*>* loopIndices)
Brian Osmanea485e52021-01-15 13:20:32 -05001022 : fLoopIndices(loopIndices) {}
1023
1024 bool visitExpression(const Expression& e) override {
1025 // A constant-(index)-expression is one of...
1026 switch (e.kind()) {
1027 // ... a literal value
1028 case Expression::Kind::kBoolLiteral:
1029 case Expression::Kind::kIntLiteral:
1030 case Expression::Kind::kFloatLiteral:
1031 return false;
1032
John Stiles532138c2021-03-04 16:29:22 -05001033 // ... settings can appear in fragment processors; they will resolve when compiled
1034 case Expression::Kind::kSetting:
1035 return false;
1036
Brian Osman7b361492021-02-25 11:25:30 -05001037 // ... a global or local variable qualified as 'const', excluding function parameters.
1038 // ... loop indices as defined in section 4. [constant-index-expression]
1039 case Expression::Kind::kVariableReference: {
1040 const Variable* v = e.as<VariableReference>().variable();
1041 if ((v->storage() == Variable::Storage::kGlobal ||
1042 v->storage() == Variable::Storage::kLocal) &&
1043 (v->modifiers().fFlags & Modifiers::kConst_Flag)) {
1044 return false;
1045 }
1046 return !fLoopIndices || fLoopIndices->find(v) == fLoopIndices->end();
1047 }
Brian Osmanea485e52021-01-15 13:20:32 -05001048
1049 // ... expressions composed of both of the above
1050 case Expression::Kind::kBinary:
John Stiles7384b372021-04-01 13:48:15 -04001051 case Expression::Kind::kConstructorArray:
John Stiles8cad6372021-04-07 12:31:13 -04001052 case Expression::Kind::kConstructorCompound:
1053 case Expression::Kind::kConstructorCompoundCast:
John Stilese1182782021-03-30 22:09:37 -04001054 case Expression::Kind::kConstructorDiagonalMatrix:
John Stiles5abb9e12021-04-06 13:47:19 -04001055 case Expression::Kind::kConstructorMatrixResize:
John Stilesfd7252f2021-04-04 22:24:40 -04001056 case Expression::Kind::kConstructorScalarCast:
John Stiles2938eea2021-04-01 18:58:25 -04001057 case Expression::Kind::kConstructorSplat:
John Stilesd47330f2021-04-08 23:25:52 -04001058 case Expression::Kind::kConstructorStruct:
Brian Osmanea485e52021-01-15 13:20:32 -05001059 case Expression::Kind::kFieldAccess:
1060 case Expression::Kind::kIndex:
1061 case Expression::Kind::kPrefix:
1062 case Expression::Kind::kPostfix:
1063 case Expression::Kind::kSwizzle:
1064 case Expression::Kind::kTernary:
1065 return INHERITED::visitExpression(e);
1066
Brian Osman7b361492021-02-25 11:25:30 -05001067 // These are completely disallowed in SkSL constant-(index)-expressions. GLSL allows
Brian Osmanea485e52021-01-15 13:20:32 -05001068 // calls to built-in functions where the arguments are all constant-expressions, but
1069 // we don't guarantee that behavior. (skbug.com/10835)
1070 case Expression::Kind::kExternalFunctionCall:
1071 case Expression::Kind::kFunctionCall:
1072 return true;
1073
1074 // These should never appear in final IR
1075 case Expression::Kind::kDefined:
1076 case Expression::Kind::kExternalFunctionReference:
1077 case Expression::Kind::kFunctionReference:
Brian Osmanea485e52021-01-15 13:20:32 -05001078 case Expression::Kind::kTypeReference:
1079 default:
1080 SkDEBUGFAIL("Unexpected expression type");
1081 return true;
1082 }
1083 }
1084
1085private:
1086 const std::set<const Variable*>* fLoopIndices;
1087 using INHERITED = ProgramVisitor;
1088};
1089
1090class ES2IndexingVisitor : public ProgramVisitor {
1091public:
1092 ES2IndexingVisitor(ErrorReporter& errors) : fErrors(errors) {}
1093
1094 bool visitStatement(const Statement& s) override {
1095 if (s.is<ForStatement>()) {
1096 const ForStatement& f = s.as<ForStatement>();
1097 SkASSERT(f.initializer() && f.initializer()->is<VarDeclaration>());
1098 const Variable* var = &f.initializer()->as<VarDeclaration>().var();
1099 auto [iter, inserted] = fLoopIndices.insert(var);
1100 SkASSERT(inserted);
1101 bool result = this->visitStatement(*f.statement());
1102 fLoopIndices.erase(iter);
1103 return result;
1104 }
1105 return INHERITED::visitStatement(s);
1106 }
1107
1108 bool visitExpression(const Expression& e) override {
1109 if (e.is<IndexExpression>()) {
1110 const IndexExpression& i = e.as<IndexExpression>();
Brian Osman7b361492021-02-25 11:25:30 -05001111 ConstantExpressionVisitor indexerInvalid(&fLoopIndices);
Brian Osmanea485e52021-01-15 13:20:32 -05001112 if (indexerInvalid.visitExpression(*i.index())) {
1113 fErrors.error(i.fOffset, "index expression must be constant");
1114 return true;
1115 }
1116 }
1117 return INHERITED::visitExpression(e);
1118 }
1119
1120 using ProgramVisitor::visitProgramElement;
1121
1122private:
1123 ErrorReporter& fErrors;
1124 std::set<const Variable*> fLoopIndices;
1125 using INHERITED = ProgramVisitor;
1126};
1127
1128
1129void Analysis::ValidateIndexingForES2(const ProgramElement& pe, ErrorReporter& errors) {
1130 ES2IndexingVisitor visitor(errors);
1131 visitor.visitProgramElement(pe);
1132}
1133
Brian Osman7b361492021-02-25 11:25:30 -05001134bool Analysis::IsConstantExpression(const Expression& expr) {
1135 ConstantExpressionVisitor visitor(/*loopIndices=*/nullptr);
1136 return !visitor.visitExpression(expr);
1137}
1138
John Stiles958f4b52021-03-17 16:39:49 -04001139bool Analysis::CanExitWithoutReturningValue(const FunctionDeclaration& funcDecl,
1140 const Statement& body) {
1141 if (funcDecl.returnType().isVoid()) {
1142 return false;
1143 }
John Stilesb3dcbb12021-03-04 16:00:20 -05001144 ReturnsOnAllPathsVisitor visitor;
John Stiles958f4b52021-03-17 16:39:49 -04001145 visitor.visitStatement(body);
John Stilesb3dcbb12021-03-04 16:00:20 -05001146 return !visitor.fFoundReturn;
1147}
1148
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001149////////////////////////////////////////////////////////////////////////////////
1150// ProgramVisitor
1151
Brian Osman133724c2020-10-28 14:14:39 -04001152bool ProgramVisitor::visit(const Program& program) {
1153 for (const ProgramElement* pe : program.elements()) {
Brian Osman1179fcf2020-10-08 16:04:40 -04001154 if (this->visitProgramElement(*pe)) {
John Stiles933abe32020-08-28 11:58:40 -04001155 return true;
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001156 }
1157 }
John Stiles933abe32020-08-28 11:58:40 -04001158 return false;
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001159}
1160
John Stiles48b25582021-03-11 14:26:42 -05001161template <typename T> bool TProgramVisitor<T>::visitExpression(typename T::Expression& e) {
John Stiles70b82422020-09-30 10:55:12 -04001162 switch (e.kind()) {
Ethan Nicholase6592142020-09-08 10:22:09 -04001163 case Expression::Kind::kBoolLiteral:
1164 case Expression::Kind::kDefined:
Brian Osmanbe0b3b72021-01-06 14:27:35 -05001165 case Expression::Kind::kExternalFunctionReference:
Ethan Nicholase6592142020-09-08 10:22:09 -04001166 case Expression::Kind::kFloatLiteral:
1167 case Expression::Kind::kFunctionReference:
1168 case Expression::Kind::kIntLiteral:
Ethan Nicholase6592142020-09-08 10:22:09 -04001169 case Expression::Kind::kSetting:
1170 case Expression::Kind::kTypeReference:
1171 case Expression::Kind::kVariableReference:
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001172 // Leaf expressions return false
1173 return false;
John Stiles70b82422020-09-30 10:55:12 -04001174
Ethan Nicholase6592142020-09-08 10:22:09 -04001175 case Expression::Kind::kBinary: {
John Stiles70b82422020-09-30 10:55:12 -04001176 auto& b = e.template as<BinaryExpression>();
John Stiles48b25582021-03-11 14:26:42 -05001177 return (b.left() && this->visitExpressionPtr(b.left())) ||
1178 (b.right() && this->visitExpressionPtr(b.right()));
John Stiles70b82422020-09-30 10:55:12 -04001179 }
John Stiles7384b372021-04-01 13:48:15 -04001180 case Expression::Kind::kConstructorArray:
John Stiles8cad6372021-04-07 12:31:13 -04001181 case Expression::Kind::kConstructorCompound:
1182 case Expression::Kind::kConstructorCompoundCast:
John Stiles2938eea2021-04-01 18:58:25 -04001183 case Expression::Kind::kConstructorDiagonalMatrix:
John Stiles5abb9e12021-04-06 13:47:19 -04001184 case Expression::Kind::kConstructorMatrixResize:
John Stilesfd7252f2021-04-04 22:24:40 -04001185 case Expression::Kind::kConstructorScalarCast:
John Stilesd47330f2021-04-08 23:25:52 -04001186 case Expression::Kind::kConstructorSplat:
1187 case Expression::Kind::kConstructorStruct: {
John Stiles7384b372021-04-01 13:48:15 -04001188 auto& c = e.asAnyConstructor();
1189 for (auto& arg : c.argumentSpan()) {
John Stiles48b25582021-03-11 14:26:42 -05001190 if (this->visitExpressionPtr(arg)) { return true; }
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001191 }
John Stiles70b82422020-09-30 10:55:12 -04001192 return false;
1193 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001194 case Expression::Kind::kExternalFunctionCall: {
John Stiles70b82422020-09-30 10:55:12 -04001195 auto& c = e.template as<ExternalFunctionCall>();
Ethan Nicholas6e86ec92020-09-30 14:29:56 -04001196 for (auto& arg : c.arguments()) {
John Stiles48b25582021-03-11 14:26:42 -05001197 if (this->visitExpressionPtr(arg)) { return true; }
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001198 }
John Stiles70b82422020-09-30 10:55:12 -04001199 return false;
1200 }
John Stilesd7ab4502020-09-24 22:41:00 -04001201 case Expression::Kind::kFieldAccess:
John Stiles48b25582021-03-11 14:26:42 -05001202 return this->visitExpressionPtr(e.template as<FieldAccess>().base());
John Stiles70b82422020-09-30 10:55:12 -04001203
Ethan Nicholase6592142020-09-08 10:22:09 -04001204 case Expression::Kind::kFunctionCall: {
John Stiles70b82422020-09-30 10:55:12 -04001205 auto& c = e.template as<FunctionCall>();
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001206 for (auto& arg : c.arguments()) {
John Stiles48b25582021-03-11 14:26:42 -05001207 if (arg && this->visitExpressionPtr(arg)) { return true; }
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001208 }
John Stiles70b82422020-09-30 10:55:12 -04001209 return false;
1210 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001211 case Expression::Kind::kIndex: {
John Stiles70b82422020-09-30 10:55:12 -04001212 auto& i = e.template as<IndexExpression>();
John Stiles48b25582021-03-11 14:26:42 -05001213 return this->visitExpressionPtr(i.base()) || this->visitExpressionPtr(i.index());
John Stiles70b82422020-09-30 10:55:12 -04001214 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001215 case Expression::Kind::kPostfix:
John Stiles48b25582021-03-11 14:26:42 -05001216 return this->visitExpressionPtr(e.template as<PostfixExpression>().operand());
John Stiles70b82422020-09-30 10:55:12 -04001217
Ethan Nicholase6592142020-09-08 10:22:09 -04001218 case Expression::Kind::kPrefix:
John Stiles48b25582021-03-11 14:26:42 -05001219 return this->visitExpressionPtr(e.template as<PrefixExpression>().operand());
John Stiles70b82422020-09-30 10:55:12 -04001220
Brian Osman010ce6a2020-10-19 16:34:10 -04001221 case Expression::Kind::kSwizzle: {
1222 auto& s = e.template as<Swizzle>();
John Stiles48b25582021-03-11 14:26:42 -05001223 return s.base() && this->visitExpressionPtr(s.base());
Brian Osman010ce6a2020-10-19 16:34:10 -04001224 }
John Stiles70b82422020-09-30 10:55:12 -04001225
Ethan Nicholase6592142020-09-08 10:22:09 -04001226 case Expression::Kind::kTernary: {
John Stiles70b82422020-09-30 10:55:12 -04001227 auto& t = e.template as<TernaryExpression>();
John Stiles48b25582021-03-11 14:26:42 -05001228 return this->visitExpressionPtr(t.test()) ||
1229 (t.ifTrue() && this->visitExpressionPtr(t.ifTrue())) ||
1230 (t.ifFalse() && this->visitExpressionPtr(t.ifFalse()));
John Stiles70b82422020-09-30 10:55:12 -04001231 }
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001232 default:
1233 SkUNREACHABLE;
1234 }
1235}
1236
John Stiles48b25582021-03-11 14:26:42 -05001237template <typename T> bool TProgramVisitor<T>::visitStatement(typename T::Statement& s) {
John Stiles70b82422020-09-30 10:55:12 -04001238 switch (s.kind()) {
Ethan Nicholase6592142020-09-08 10:22:09 -04001239 case Statement::Kind::kBreak:
1240 case Statement::Kind::kContinue:
1241 case Statement::Kind::kDiscard:
John Stiles98c1f822020-09-09 14:18:53 -04001242 case Statement::Kind::kInlineMarker:
Ethan Nicholase6592142020-09-08 10:22:09 -04001243 case Statement::Kind::kNop:
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001244 // Leaf statements just return false
1245 return false;
John Stiles70b82422020-09-30 10:55:12 -04001246
Ethan Nicholase6592142020-09-08 10:22:09 -04001247 case Statement::Kind::kBlock:
John Stiles70b82422020-09-30 10:55:12 -04001248 for (auto& stmt : s.template as<Block>().children()) {
John Stiles48b25582021-03-11 14:26:42 -05001249 if (stmt && this->visitStatementPtr(stmt)) {
Ethan Nicholas7bd60432020-09-25 14:31:59 -04001250 return true;
1251 }
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001252 }
1253 return false;
John Stiles70b82422020-09-30 10:55:12 -04001254
John Stilesa0e56e32021-03-03 13:14:37 -05001255 case Statement::Kind::kSwitchCase: {
1256 auto& sc = s.template as<SwitchCase>();
John Stiles48b25582021-03-11 14:26:42 -05001257 if (sc.value() && this->visitExpressionPtr(sc.value())) {
John Stilesa0e56e32021-03-03 13:14:37 -05001258 return true;
1259 }
John Stiles48b25582021-03-11 14:26:42 -05001260 return this->visitStatementPtr(sc.statement());
John Stilesa0e56e32021-03-03 13:14:37 -05001261 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001262 case Statement::Kind::kDo: {
John Stiles70b82422020-09-30 10:55:12 -04001263 auto& d = s.template as<DoStatement>();
John Stiles48b25582021-03-11 14:26:42 -05001264 return this->visitExpressionPtr(d.test()) || this->visitStatementPtr(d.statement());
John Stiles70b82422020-09-30 10:55:12 -04001265 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001266 case Statement::Kind::kExpression:
John Stiles48b25582021-03-11 14:26:42 -05001267 return this->visitExpressionPtr(s.template as<ExpressionStatement>().expression());
John Stiles70b82422020-09-30 10:55:12 -04001268
Ethan Nicholase6592142020-09-08 10:22:09 -04001269 case Statement::Kind::kFor: {
John Stiles70b82422020-09-30 10:55:12 -04001270 auto& f = s.template as<ForStatement>();
John Stiles48b25582021-03-11 14:26:42 -05001271 return (f.initializer() && this->visitStatementPtr(f.initializer())) ||
1272 (f.test() && this->visitExpressionPtr(f.test())) ||
1273 (f.next() && this->visitExpressionPtr(f.next())) ||
1274 this->visitStatementPtr(f.statement());
John Stiles70b82422020-09-30 10:55:12 -04001275 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001276 case Statement::Kind::kIf: {
John Stiles70b82422020-09-30 10:55:12 -04001277 auto& i = s.template as<IfStatement>();
John Stiles48b25582021-03-11 14:26:42 -05001278 return (i.test() && this->visitExpressionPtr(i.test())) ||
1279 (i.ifTrue() && this->visitStatementPtr(i.ifTrue())) ||
1280 (i.ifFalse() && this->visitStatementPtr(i.ifFalse()));
John Stiles70b82422020-09-30 10:55:12 -04001281 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001282 case Statement::Kind::kReturn: {
John Stiles70b82422020-09-30 10:55:12 -04001283 auto& r = s.template as<ReturnStatement>();
John Stiles48b25582021-03-11 14:26:42 -05001284 return r.expression() && this->visitExpressionPtr(r.expression());
John Stiles70b82422020-09-30 10:55:12 -04001285 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001286 case Statement::Kind::kSwitch: {
John Stiles70b82422020-09-30 10:55:12 -04001287 auto& sw = s.template as<SwitchStatement>();
John Stiles48b25582021-03-11 14:26:42 -05001288 if (this->visitExpressionPtr(sw.value())) {
John Stiles70b82422020-09-30 10:55:12 -04001289 return true;
1290 }
John Stiles48b25582021-03-11 14:26:42 -05001291 for (auto& c : sw.cases()) {
1292 if (this->visitStatementPtr(c)) {
John Stiles70b82422020-09-30 10:55:12 -04001293 return true;
1294 }
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001295 }
John Stiles70b82422020-09-30 10:55:12 -04001296 return false;
1297 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001298 case Statement::Kind::kVarDeclaration: {
John Stiles70b82422020-09-30 10:55:12 -04001299 auto& v = s.template as<VarDeclaration>();
John Stiles48b25582021-03-11 14:26:42 -05001300 return v.value() && this->visitExpressionPtr(v.value());
John Stiles70b82422020-09-30 10:55:12 -04001301 }
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001302 default:
1303 SkUNREACHABLE;
1304 }
1305}
1306
John Stiles48b25582021-03-11 14:26:42 -05001307template <typename T> bool TProgramVisitor<T>::visitProgramElement(typename T::ProgramElement& pe) {
John Stiles70b82422020-09-30 10:55:12 -04001308 switch (pe.kind()) {
Ethan Nicholase6592142020-09-08 10:22:09 -04001309 case ProgramElement::Kind::kEnum:
1310 case ProgramElement::Kind::kExtension:
John Stiles569249b2020-11-03 12:18:22 -05001311 case ProgramElement::Kind::kFunctionPrototype:
John Stilesd39aec02020-12-03 10:42:26 -05001312 case ProgramElement::Kind::kInterfaceBlock:
Ethan Nicholase6592142020-09-08 10:22:09 -04001313 case ProgramElement::Kind::kModifiers:
1314 case ProgramElement::Kind::kSection:
John Stilesdc75a972020-11-25 16:24:55 -05001315 case ProgramElement::Kind::kStructDefinition:
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001316 // Leaf program elements just return false by default
1317 return false;
John Stiles70b82422020-09-30 10:55:12 -04001318
Ethan Nicholase6592142020-09-08 10:22:09 -04001319 case ProgramElement::Kind::kFunction:
John Stiles48b25582021-03-11 14:26:42 -05001320 return this->visitStatementPtr(pe.template as<FunctionDefinition>().body());
John Stiles70b82422020-09-30 10:55:12 -04001321
Brian Osmanc0213602020-10-06 14:43:32 -04001322 case ProgramElement::Kind::kGlobalVar:
John Stiles48b25582021-03-11 14:26:42 -05001323 return this->visitStatementPtr(pe.template as<GlobalVarDeclaration>().declaration());
John Stiles70b82422020-09-30 10:55:12 -04001324
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001325 default:
1326 SkUNREACHABLE;
1327 }
1328}
1329
John Stiles48b25582021-03-11 14:26:42 -05001330template class TProgramVisitor<ProgramVisitorTypes>;
1331template class TProgramVisitor<ProgramWriterTypes>;
John Stiles70b82422020-09-30 10:55:12 -04001332
John Stilesa6841be2020-08-06 14:11:56 -04001333} // namespace SkSL