blob: 4865c5daaa34bbc1ae407949d5c1e462961e4ecd [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 Osman4d571112021-04-27 09:10:10 -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
Brian Osman8cdf28f2021-05-24 09:52:39 -040086 int elidedSampleCoordCount() const { return fElidedSampleCoordCount; }
87
Michael Ludwig8f3a8362020-06-29 17:27:00 -040088protected:
John Stiles933abe32020-08-28 11:58:40 -040089 const Context& fContext;
Michael Ludwig8f3a8362020-06-29 17:27:00 -040090 const Variable& fFP;
Brian Osman4d571112021-04-27 09:10:10 -040091 const bool fWritesToSampleCoords;
Brian Osman1298bc42020-06-30 13:39:35 -040092 SampleUsage fUsage;
Brian Osman8cdf28f2021-05-24 09:52:39 -040093 int fElidedSampleCoordCount = 0;
Michael Ludwig8f3a8362020-06-29 17:27:00 -040094
95 bool visitExpression(const Expression& e) override {
Brian Osman09622682021-04-15 14:43:19 -040096 // Looking for sample(fp, ...)
97 if (e.is<FunctionCall>()) {
John Stiles403a3632020-08-20 12:11:48 -040098 const FunctionCall& fc = e.as<FunctionCall>();
Brian Osman1298bc42020-06-30 13:39:35 -040099 if (is_sample_call_to_fp(fc, fFP)) {
100 // Determine the type of call at this site, and merge it with the accumulated state
Brian Osman09622682021-04-15 14:43:19 -0400101 if (fc.arguments().size() >= 2) {
102 const Expression* coords = fc.arguments()[1].get();
103 if (coords->type() == *fContext.fTypes.fFloat2) {
Brian Osman4d571112021-04-27 09:10:10 -0400104 // If the coords are a direct reference to the program's sample-coords,
105 // and those coords are never modified, we can conservatively turn this
106 // into PassThrough sampling. In all other cases, we consider it Explicit.
107 if (!fWritesToSampleCoords && coords->is<VariableReference>() &&
108 coords->as<VariableReference>()
109 .variable()
110 ->modifiers()
111 .fLayout.fBuiltin == SK_MAIN_COORDS_BUILTIN) {
112 fUsage.merge(SampleUsage::PassThrough());
Brian Osman8cdf28f2021-05-24 09:52:39 -0400113 ++fElidedSampleCoordCount;
Brian Osman4d571112021-04-27 09:10:10 -0400114 } else {
115 fUsage.merge(SampleUsage::Explicit());
116 }
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400117 } else {
Brian Osman09622682021-04-15 14:43:19 -0400118 // sample(fp, half4 inputColor) -> PassThrough
119 fUsage.merge(SampleUsage::PassThrough());
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400120 }
121 } else {
Brian Osman09622682021-04-15 14:43:19 -0400122 // sample(fp) -> PassThrough
Brian Osman1298bc42020-06-30 13:39:35 -0400123 fUsage.merge(SampleUsage::PassThrough());
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400124 }
Brian Osman1298bc42020-06-30 13:39:35 -0400125 // NOTE: we don't return true here just because we found a sample call. We need to
Brian Osman09622682021-04-15 14:43:19 -0400126 // process the entire program and merge across all encountered calls.
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400127 }
128 }
129
John Stilesd7ab4502020-09-24 22:41:00 -0400130 return INHERITED::visitExpression(e);
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400131 }
132
John Stiles7571f9e2020-09-02 22:42:33 -0400133 using INHERITED = ProgramVisitor;
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400134};
135
Brian Osman92aac1e2020-08-05 16:48:58 -0400136// Visitor that searches through the program for references to a particular builtin variable
137class BuiltinVariableVisitor : public ProgramVisitor {
138public:
139 BuiltinVariableVisitor(int builtin) : fBuiltin(builtin) {}
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400140
141 bool visitExpression(const Expression& e) override {
Brian Osman79457ef2020-09-24 15:01:27 -0400142 if (e.is<VariableReference>()) {
John Stiles403a3632020-08-20 12:11:48 -0400143 const VariableReference& var = e.as<VariableReference>();
Ethan Nicholas78686922020-10-08 06:46:27 -0400144 return var.variable()->modifiers().fLayout.fBuiltin == fBuiltin;
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400145 }
John Stilesd7ab4502020-09-24 22:41:00 -0400146 return INHERITED::visitExpression(e);
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400147 }
148
Brian Osman92aac1e2020-08-05 16:48:58 -0400149 int fBuiltin;
150
John Stiles7571f9e2020-09-02 22:42:33 -0400151 using INHERITED = ProgramVisitor;
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400152};
153
Brian Osman04d79fc2021-07-02 13:25:35 -0400154// Visitor that searches for calls to sample() from a function other than main()
155class SampleOutsideMainVisitor : public ProgramVisitor {
156public:
157 SampleOutsideMainVisitor() {}
158
159 bool visitExpression(const Expression& e) override {
160 if (e.is<FunctionCall>()) {
161 const FunctionDeclaration& f = e.as<FunctionCall>().function();
162 if (f.isBuiltin() && f.name() == "sample") {
163 return true;
164 }
165 }
166 return INHERITED::visitExpression(e);
167 }
168
169 bool visitProgramElement(const ProgramElement& p) override {
170 return p.is<FunctionDefinition>() &&
171 !p.as<FunctionDefinition>().declaration().isMain() &&
172 INHERITED::visitProgramElement(p);
173 }
174
175 using INHERITED = ProgramVisitor;
176};
177
Ethan Nicholas6e0fa402020-08-20 14:08:23 -0400178// Visitor that counts the number of nodes visited
179class NodeCountVisitor : public ProgramVisitor {
180public:
John Stiles2c1e4922020-10-01 09:14:14 -0400181 NodeCountVisitor(int limit) : fLimit(limit) {}
182
Ethan Nicholas6e0fa402020-08-20 14:08:23 -0400183 int visit(const Statement& s) {
Ethan Nicholas6e0fa402020-08-20 14:08:23 -0400184 this->visitStatement(s);
185 return fCount;
186 }
187
188 bool visitExpression(const Expression& e) override {
189 ++fCount;
John Stiles9b9415e2020-11-23 14:48:06 -0500190 return (fCount >= fLimit) || INHERITED::visitExpression(e);
Ethan Nicholas6e0fa402020-08-20 14:08:23 -0400191 }
192
193 bool visitProgramElement(const ProgramElement& p) override {
194 ++fCount;
John Stiles9b9415e2020-11-23 14:48:06 -0500195 return (fCount >= fLimit) || INHERITED::visitProgramElement(p);
Ethan Nicholas6e0fa402020-08-20 14:08:23 -0400196 }
197
198 bool visitStatement(const Statement& s) override {
199 ++fCount;
John Stiles9b9415e2020-11-23 14:48:06 -0500200 return (fCount >= fLimit) || INHERITED::visitStatement(s);
Ethan Nicholas6e0fa402020-08-20 14:08:23 -0400201 }
202
203private:
John Stiles2c1e4922020-10-01 09:14:14 -0400204 int fCount = 0;
205 int fLimit;
Ethan Nicholas6e0fa402020-08-20 14:08:23 -0400206
John Stiles7571f9e2020-09-02 22:42:33 -0400207 using INHERITED = ProgramVisitor;
Ethan Nicholas6e0fa402020-08-20 14:08:23 -0400208};
209
Brian Osman010ce6a2020-10-19 16:34:10 -0400210class ProgramUsageVisitor : public ProgramVisitor {
Brian Osman2e25ff42020-10-15 10:32:04 -0400211public:
Brian Osman010ce6a2020-10-19 16:34:10 -0400212 ProgramUsageVisitor(ProgramUsage* usage, int delta) : fUsage(usage), fDelta(delta) {}
213
John Stiles39465b82021-03-18 09:19:55 -0400214 bool visitProgramElement(const ProgramElement& pe) override {
215 if (pe.is<FunctionDefinition>()) {
216 for (const Variable* param : pe.as<FunctionDefinition>().declaration().parameters()) {
217 // Ensure function-parameter variables exist in the variable usage map. They aren't
218 // otherwise declared, but ProgramUsage::get() should be able to find them, even if
219 // they are unread and unwritten.
220 fUsage->fVariableCounts[param];
221 }
John Stiles8e2a84b2021-04-19 09:35:38 -0400222 } else if (pe.is<InterfaceBlock>()) {
223 // Ensure interface-block variables exist in the variable usage map.
224 fUsage->fVariableCounts[&pe.as<InterfaceBlock>().variable()];
John Stiles39465b82021-03-18 09:19:55 -0400225 }
226 return INHERITED::visitProgramElement(pe);
227 }
228
John Stiles04a8a542021-03-10 19:03:26 -0500229 bool visitStatement(const Statement& s) override {
230 if (s.is<VarDeclaration>()) {
231 // Add all declared variables to the usage map (even if never otherwise accessed).
232 const VarDeclaration& vd = s.as<VarDeclaration>();
233 ProgramUsage::VariableCounts& counts = fUsage->fVariableCounts[&vd.var()];
234 counts.fDeclared += fDelta;
235 SkASSERT(counts.fDeclared >= 0);
236 if (vd.value()) {
237 // The initial-value expression, when present, counts as a write.
238 counts.fWrite += fDelta;
239 }
240 }
241 return INHERITED::visitStatement(s);
242 }
243
Brian Osman2e25ff42020-10-15 10:32:04 -0400244 bool visitExpression(const Expression& e) override {
245 if (e.is<FunctionCall>()) {
246 const FunctionDeclaration* f = &e.as<FunctionCall>().function();
Brian Osman010ce6a2020-10-19 16:34:10 -0400247 fUsage->fCallCounts[f] += fDelta;
248 SkASSERT(fUsage->fCallCounts[f] >= 0);
249 } else if (e.is<VariableReference>()) {
250 const VariableReference& ref = e.as<VariableReference>();
251 ProgramUsage::VariableCounts& counts = fUsage->fVariableCounts[ref.variable()];
252 switch (ref.refKind()) {
253 case VariableRefKind::kRead:
254 counts.fRead += fDelta;
255 break;
256 case VariableRefKind::kWrite:
257 counts.fWrite += fDelta;
258 break;
259 case VariableRefKind::kReadWrite:
260 case VariableRefKind::kPointer:
261 counts.fRead += fDelta;
262 counts.fWrite += fDelta;
263 break;
264 }
265 SkASSERT(counts.fRead >= 0 && counts.fWrite >= 0);
Brian Osman2e25ff42020-10-15 10:32:04 -0400266 }
267 return INHERITED::visitExpression(e);
268 }
269
Brian Osman010ce6a2020-10-19 16:34:10 -0400270 using ProgramVisitor::visitProgramElement;
271 using ProgramVisitor::visitStatement;
272
273 ProgramUsage* fUsage;
274 int fDelta;
Brian Osman2e25ff42020-10-15 10:32:04 -0400275 using INHERITED = ProgramVisitor;
276};
277
Ethan Nicholas765d2fe2020-08-26 08:29:55 -0400278class VariableWriteVisitor : public ProgramVisitor {
279public:
280 VariableWriteVisitor(const Variable* var)
281 : fVar(var) {}
282
283 bool visit(const Statement& s) {
284 return this->visitStatement(s);
285 }
286
287 bool visitExpression(const Expression& e) override {
Brian Osman79457ef2020-09-24 15:01:27 -0400288 if (e.is<VariableReference>()) {
Ethan Nicholas765d2fe2020-08-26 08:29:55 -0400289 const VariableReference& ref = e.as<VariableReference>();
Ethan Nicholas453f67f2020-10-09 10:43:45 -0400290 if (ref.variable() == fVar &&
291 (ref.refKind() == VariableReference::RefKind::kWrite ||
292 ref.refKind() == VariableReference::RefKind::kReadWrite ||
293 ref.refKind() == VariableReference::RefKind::kPointer)) {
Ethan Nicholas765d2fe2020-08-26 08:29:55 -0400294 return true;
295 }
296 }
John Stilesd7ab4502020-09-24 22:41:00 -0400297 return INHERITED::visitExpression(e);
Ethan Nicholas765d2fe2020-08-26 08:29:55 -0400298 }
299
300private:
301 const Variable* fVar;
302
John Stiles7571f9e2020-09-02 22:42:33 -0400303 using INHERITED = ProgramVisitor;
Ethan Nicholas765d2fe2020-08-26 08:29:55 -0400304};
305
John Stilesa976da72020-09-25 23:06:26 -0400306// If a caller doesn't care about errors, we can use this trivial reporter that just counts up.
307class TrivialErrorReporter : public ErrorReporter {
308public:
309 void error(int offset, String) override { ++fErrorCount; }
310 int errorCount() override { return fErrorCount; }
John Stiles8d3642e2021-01-22 09:50:04 -0500311 void setErrorCount(int c) override { fErrorCount = c; }
John Stilesa976da72020-09-25 23:06:26 -0400312
313private:
314 int fErrorCount = 0;
315};
316
John Stilesdce4d3e2020-09-25 14:35:13 -0400317// This isn't actually using ProgramVisitor, because it only considers a subset of the fields for
318// any given expression kind. For instance, when indexing an array (e.g. `x[1]`), we only want to
319// know if the base (`x`) is assignable; the index expression (`1`) doesn't need to be.
320class IsAssignableVisitor {
321public:
John Stilesb21fac22020-12-04 15:36:49 -0500322 IsAssignableVisitor(ErrorReporter* errors) : fErrors(errors) {}
John Stilesdce4d3e2020-09-25 14:35:13 -0400323
John Stilesb21fac22020-12-04 15:36:49 -0500324 bool visit(Expression& expr, Analysis::AssignmentInfo* info) {
Ethan Nicholas67a0a8a2021-01-13 12:36:02 -0500325 int oldErrorCount = fErrors->errorCount();
John Stilesdce4d3e2020-09-25 14:35:13 -0400326 this->visitExpression(expr);
John Stilesb21fac22020-12-04 15:36:49 -0500327 if (info) {
328 info->fAssignedVar = fAssignedVar;
John Stilesb21fac22020-12-04 15:36:49 -0500329 }
Ethan Nicholas67a0a8a2021-01-13 12:36:02 -0500330 return fErrors->errorCount() == oldErrorCount;
John Stilesdce4d3e2020-09-25 14:35:13 -0400331 }
332
333 void visitExpression(Expression& expr) {
334 switch (expr.kind()) {
335 case Expression::Kind::kVariableReference: {
336 VariableReference& varRef = expr.as<VariableReference>();
Ethan Nicholas78686922020-10-08 06:46:27 -0400337 const Variable* var = varRef.variable();
Brian Osmane49703f2021-04-19 11:15:24 -0400338 if (var->modifiers().fFlags & (Modifiers::kConst_Flag | Modifiers::kUniform_Flag)) {
John Stilesa976da72020-09-25 23:06:26 -0400339 fErrors->error(expr.fOffset,
Ethan Nicholase2c49992020-10-05 11:49:11 -0400340 "cannot modify immutable variable '" + var->name() + "'");
John Stilesb21fac22020-12-04 15:36:49 -0500341 } else {
342 SkASSERT(fAssignedVar == nullptr);
343 fAssignedVar = &varRef;
John Stilesdce4d3e2020-09-25 14:35:13 -0400344 }
345 break;
346 }
347 case Expression::Kind::kFieldAccess:
Ethan Nicholas7a95b202020-10-09 11:55:40 -0400348 this->visitExpression(*expr.as<FieldAccess>().base());
John Stilesdce4d3e2020-09-25 14:35:13 -0400349 break;
350
351 case Expression::Kind::kSwizzle: {
352 const Swizzle& swizzle = expr.as<Swizzle>();
353 this->checkSwizzleWrite(swizzle);
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400354 this->visitExpression(*swizzle.base());
John Stilesdce4d3e2020-09-25 14:35:13 -0400355 break;
356 }
John Stiles47c0a742021-02-09 09:30:35 -0500357 case Expression::Kind::kIndex:
358 this->visitExpression(*expr.as<IndexExpression>().base());
John Stilesdce4d3e2020-09-25 14:35:13 -0400359 break;
John Stiles47c0a742021-02-09 09:30:35 -0500360
John Stilesdce4d3e2020-09-25 14:35:13 -0400361 default:
John Stilesa976da72020-09-25 23:06:26 -0400362 fErrors->error(expr.fOffset, "cannot assign to this expression");
John Stilesdce4d3e2020-09-25 14:35:13 -0400363 break;
364 }
365 }
366
367private:
368 void checkSwizzleWrite(const Swizzle& swizzle) {
369 int bits = 0;
John Stiles6e88e042021-02-19 14:09:38 -0500370 for (int8_t idx : swizzle.components()) {
371 SkASSERT(idx >= SwizzleComponent::X && idx <= SwizzleComponent::W);
John Stilesdce4d3e2020-09-25 14:35:13 -0400372 int bit = 1 << idx;
373 if (bits & bit) {
John Stilesa976da72020-09-25 23:06:26 -0400374 fErrors->error(swizzle.fOffset,
375 "cannot write to the same swizzle field more than once");
John Stilesdce4d3e2020-09-25 14:35:13 -0400376 break;
377 }
378 bits |= bit;
379 }
380 }
381
John Stilesa976da72020-09-25 23:06:26 -0400382 ErrorReporter* fErrors;
John Stilesb21fac22020-12-04 15:36:49 -0500383 VariableReference* fAssignedVar = nullptr;
John Stilesdce4d3e2020-09-25 14:35:13 -0400384
385 using INHERITED = ProgramVisitor;
386};
387
John Stiles642cde22021-02-23 14:57:01 -0500388class SwitchCaseContainsExit : public ProgramVisitor {
389public:
390 SwitchCaseContainsExit(bool conditionalExits) : fConditionalExits(conditionalExits) {}
391
392 bool visitStatement(const Statement& stmt) override {
393 switch (stmt.kind()) {
394 case Statement::Kind::kBlock:
John Stilesa0e56e32021-03-03 13:14:37 -0500395 case Statement::Kind::kSwitchCase:
John Stiles642cde22021-02-23 14:57:01 -0500396 return INHERITED::visitStatement(stmt);
397
398 case Statement::Kind::kReturn:
399 // Returns are an early exit regardless of the surrounding control structures.
400 return fConditionalExits ? fInConditional : !fInConditional;
401
402 case Statement::Kind::kContinue:
403 // Continues are an early exit from switches, but not loops.
404 return !fInLoop &&
405 (fConditionalExits ? fInConditional : !fInConditional);
406
407 case Statement::Kind::kBreak:
408 // Breaks cannot escape from switches or loops.
409 return !fInLoop && !fInSwitch &&
410 (fConditionalExits ? fInConditional : !fInConditional);
411
412 case Statement::Kind::kIf: {
413 ++fInConditional;
414 bool result = INHERITED::visitStatement(stmt);
415 --fInConditional;
416 return result;
417 }
418
419 case Statement::Kind::kFor:
420 case Statement::Kind::kDo: {
421 // Loops are treated as conditionals because a loop could potentially execute zero
422 // times. We don't have a straightforward way to determine that a loop definitely
423 // executes at least once.
424 ++fInConditional;
425 ++fInLoop;
426 bool result = INHERITED::visitStatement(stmt);
427 --fInLoop;
428 --fInConditional;
429 return result;
430 }
431
432 case Statement::Kind::kSwitch: {
433 ++fInSwitch;
434 bool result = INHERITED::visitStatement(stmt);
435 --fInSwitch;
436 return result;
437 }
438
439 default:
440 return false;
441 }
442 }
443
444 bool fConditionalExits = false;
445 int fInConditional = 0;
446 int fInLoop = 0;
447 int fInSwitch = 0;
448 using INHERITED = ProgramVisitor;
449};
450
John Stilesb3dcbb12021-03-04 16:00:20 -0500451class ReturnsOnAllPathsVisitor : public ProgramVisitor {
452public:
453 bool visitExpression(const Expression& expr) override {
454 // We can avoid processing expressions entirely.
455 return false;
456 }
457
458 bool visitStatement(const Statement& stmt) override {
459 switch (stmt.kind()) {
460 // Returns, breaks, or continues will stop the scan, so only one of these should ever be
461 // true.
462 case Statement::Kind::kReturn:
463 fFoundReturn = true;
464 return true;
465
466 case Statement::Kind::kBreak:
467 fFoundBreak = true;
468 return true;
469
470 case Statement::Kind::kContinue:
471 fFoundContinue = true;
472 return true;
473
474 case Statement::Kind::kIf: {
475 const IfStatement& i = stmt.as<IfStatement>();
476 ReturnsOnAllPathsVisitor trueVisitor;
477 ReturnsOnAllPathsVisitor falseVisitor;
478 trueVisitor.visitStatement(*i.ifTrue());
479 if (i.ifFalse()) {
480 falseVisitor.visitStatement(*i.ifFalse());
481 }
482 // If either branch leads to a break or continue, we report the entire if as
483 // containing a break or continue, since we don't know which side will be reached.
484 fFoundBreak = (trueVisitor.fFoundBreak || falseVisitor.fFoundBreak);
485 fFoundContinue = (trueVisitor.fFoundContinue || falseVisitor.fFoundContinue);
486 // On the other hand, we only want to report returns that definitely happen, so we
487 // require those to be found on both sides.
488 fFoundReturn = (trueVisitor.fFoundReturn && falseVisitor.fFoundReturn);
489 return fFoundBreak || fFoundContinue || fFoundReturn;
490 }
491 case Statement::Kind::kFor: {
492 const ForStatement& f = stmt.as<ForStatement>();
493 // We assume a for/while loop runs for at least one iteration; this isn't strictly
494 // guaranteed, but it's better to be slightly over-permissive here than to fail on
495 // reasonable code.
496 ReturnsOnAllPathsVisitor forVisitor;
497 forVisitor.visitStatement(*f.statement());
498 // A for loop that contains a break or continue is safe; it won't exit the entire
499 // function, just the loop. So we disregard those signals.
500 fFoundReturn = forVisitor.fFoundReturn;
501 return fFoundReturn;
502 }
503 case Statement::Kind::kDo: {
504 const DoStatement& d = stmt.as<DoStatement>();
505 // Do-while blocks are always entered at least once.
506 ReturnsOnAllPathsVisitor doVisitor;
507 doVisitor.visitStatement(*d.statement());
508 // A do-while loop that contains a break or continue is safe; it won't exit the
509 // entire function, just the loop. So we disregard those signals.
510 fFoundReturn = doVisitor.fFoundReturn;
511 return fFoundReturn;
512 }
513 case Statement::Kind::kBlock:
514 // Blocks are definitely entered and don't imply any additional control flow.
515 // If the block contains a break, continue or return, we want to keep that.
516 return INHERITED::visitStatement(stmt);
517
518 case Statement::Kind::kSwitch: {
519 // Switches are the most complex control flow we need to deal with; fortunately we
520 // already have good primitives for dissecting them. We need to verify that:
521 // - a default case exists, so that every possible input value is covered
522 // - every switch-case either (a) returns unconditionally, or
523 // (b) falls through to another case that does
524 const SwitchStatement& s = stmt.as<SwitchStatement>();
525 bool foundDefault = false;
526 bool fellThrough = false;
John Stilesb23a64b2021-03-11 08:27:59 -0500527 for (const std::unique_ptr<Statement>& stmt : s.cases()) {
John Stilesb3dcbb12021-03-04 16:00:20 -0500528 // The default case is indicated by a null value. A switch without a default
529 // case cannot definitively return, as its value might not be in the cases list.
John Stilesb23a64b2021-03-11 08:27:59 -0500530 const SwitchCase& sc = stmt->as<SwitchCase>();
531 if (!sc.value()) {
John Stilesb3dcbb12021-03-04 16:00:20 -0500532 foundDefault = true;
533 }
534 // Scan this switch-case for any exit (break, continue or return).
535 ReturnsOnAllPathsVisitor caseVisitor;
John Stilesb23a64b2021-03-11 08:27:59 -0500536 caseVisitor.visitStatement(sc);
John Stilesb3dcbb12021-03-04 16:00:20 -0500537
538 // If we found a break or continue, whether conditional or not, this switch case
539 // can't be called an unconditional return. Switches absorb breaks but not
540 // continues.
541 if (caseVisitor.fFoundContinue) {
542 fFoundContinue = true;
543 return false;
544 }
545 if (caseVisitor.fFoundBreak) {
546 return false;
547 }
548 // We just confirmed that there weren't any breaks or continues. If we didn't
549 // find an unconditional return either, the switch is considered fallen-through.
550 // (There might be a conditional return, but that doesn't count.)
551 fellThrough = !caseVisitor.fFoundReturn;
552 }
553
554 // If we didn't find a default case, or the very last case fell through, this switch
555 // doesn't meet our criteria.
556 if (fellThrough || !foundDefault) {
557 return false;
558 }
559
560 // We scanned the entire switch, found a default case, and every section either fell
561 // through or contained an unconditional return.
562 fFoundReturn = true;
563 return true;
564 }
565
566 case Statement::Kind::kSwitchCase:
567 // Recurse into the switch-case.
568 return INHERITED::visitStatement(stmt);
569
570 case Statement::Kind::kDiscard:
571 case Statement::Kind::kExpression:
572 case Statement::Kind::kInlineMarker:
573 case Statement::Kind::kNop:
574 case Statement::Kind::kVarDeclaration:
575 // None of these statements could contain a return.
576 break;
577 }
578
579 return false;
580 }
581
582 bool fFoundReturn = false;
583 bool fFoundBreak = false;
584 bool fFoundContinue = false;
585
586 using INHERITED = ProgramVisitor;
587};
588
John Stilesa6841be2020-08-06 14:11:56 -0400589} // namespace
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400590
591////////////////////////////////////////////////////////////////////////////////
592// Analysis
593
Brian Osman4d571112021-04-27 09:10:10 -0400594SampleUsage Analysis::GetSampleUsage(const Program& program,
595 const Variable& fp,
Brian Osman8cdf28f2021-05-24 09:52:39 -0400596 bool writesToSampleCoords,
597 int* elidedSampleCoordCount) {
Brian Osman4d571112021-04-27 09:10:10 -0400598 MergeSampleUsageVisitor visitor(*program.fContext, fp, writesToSampleCoords);
Brian Osman8cdf28f2021-05-24 09:52:39 -0400599 SampleUsage result = visitor.visit(program);
600 if (elidedSampleCoordCount) {
601 *elidedSampleCoordCount += visitor.elidedSampleCoordCount();
602 }
603 return result;
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400604}
605
Brian Osman92aac1e2020-08-05 16:48:58 -0400606bool Analysis::ReferencesBuiltin(const Program& program, int builtin) {
607 BuiltinVariableVisitor visitor(builtin);
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400608 return visitor.visit(program);
609}
610
Brian Osman92aac1e2020-08-05 16:48:58 -0400611bool Analysis::ReferencesSampleCoords(const Program& program) {
612 return Analysis::ReferencesBuiltin(program, SK_MAIN_COORDS_BUILTIN);
613}
614
615bool Analysis::ReferencesFragCoords(const Program& program) {
616 return Analysis::ReferencesBuiltin(program, SK_FRAGCOORD_BUILTIN);
617}
618
Brian Osman04d79fc2021-07-02 13:25:35 -0400619bool Analysis::CallsSampleOutsideMain(const Program& program) {
620 SampleOutsideMainVisitor visitor;
621 return visitor.visit(program);
622}
623
John Stiles9b9415e2020-11-23 14:48:06 -0500624int Analysis::NodeCountUpToLimit(const FunctionDefinition& function, int limit) {
625 return NodeCountVisitor{limit}.visit(*function.body());
Ethan Nicholas6e0fa402020-08-20 14:08:23 -0400626}
627
John Stiles642cde22021-02-23 14:57:01 -0500628bool Analysis::SwitchCaseContainsUnconditionalExit(Statement& stmt) {
629 return SwitchCaseContainsExit{/*conditionalExits=*/false}.visitStatement(stmt);
630}
631
632bool Analysis::SwitchCaseContainsConditionalExit(Statement& stmt) {
633 return SwitchCaseContainsExit{/*conditionalExits=*/true}.visitStatement(stmt);
634}
635
Brian Osman010ce6a2020-10-19 16:34:10 -0400636std::unique_ptr<ProgramUsage> Analysis::GetUsage(const Program& program) {
637 auto usage = std::make_unique<ProgramUsage>();
638 ProgramUsageVisitor addRefs(usage.get(), /*delta=*/+1);
639 addRefs.visit(program);
640 return usage;
641}
642
Brian Osman0006ad02020-11-18 15:38:39 -0500643std::unique_ptr<ProgramUsage> Analysis::GetUsage(const LoadedModule& module) {
644 auto usage = std::make_unique<ProgramUsage>();
645 ProgramUsageVisitor addRefs(usage.get(), /*delta=*/+1);
646 for (const auto& element : module.fElements) {
647 addRefs.visitProgramElement(*element);
648 }
649 return usage;
650}
651
Brian Osman010ce6a2020-10-19 16:34:10 -0400652ProgramUsage::VariableCounts ProgramUsage::get(const Variable& v) const {
John Stiles04a8a542021-03-10 19:03:26 -0500653 const VariableCounts* counts = fVariableCounts.find(&v);
654 SkASSERT(counts);
655 return *counts;
Brian Osman010ce6a2020-10-19 16:34:10 -0400656}
657
658bool ProgramUsage::isDead(const Variable& v) const {
659 const Modifiers& modifiers = v.modifiers();
660 VariableCounts counts = this->get(v);
661 if ((v.storage() != Variable::Storage::kLocal && counts.fRead) ||
Brian Osmane49703f2021-04-19 11:15:24 -0400662 (modifiers.fFlags &
663 (Modifiers::kIn_Flag | Modifiers::kOut_Flag | Modifiers::kUniform_Flag))) {
Brian Osman010ce6a2020-10-19 16:34:10 -0400664 return false;
665 }
John Stilesf10eff32021-03-16 10:57:55 -0400666 // Consider the variable dead if it's never read and never written (besides the initial-value).
667 return !counts.fRead && (counts.fWrite <= (v.initialValue() ? 1 : 0));
Brian Osman010ce6a2020-10-19 16:34:10 -0400668}
669
670int ProgramUsage::get(const FunctionDeclaration& f) const {
671 const int* count = fCallCounts.find(&f);
672 return count ? *count : 0;
673}
674
675void ProgramUsage::replace(const Expression* oldExpr, const Expression* newExpr) {
676 if (oldExpr) {
677 ProgramUsageVisitor subRefs(this, /*delta=*/-1);
678 subRefs.visitExpression(*oldExpr);
679 }
680 if (newExpr) {
681 ProgramUsageVisitor addRefs(this, /*delta=*/+1);
682 addRefs.visitExpression(*newExpr);
683 }
684}
685
686void ProgramUsage::add(const Statement* stmt) {
687 ProgramUsageVisitor addRefs(this, /*delta=*/+1);
688 addRefs.visitStatement(*stmt);
689}
690
691void ProgramUsage::remove(const Expression* expr) {
692 ProgramUsageVisitor subRefs(this, /*delta=*/-1);
693 subRefs.visitExpression(*expr);
694}
695
696void ProgramUsage::remove(const Statement* stmt) {
697 ProgramUsageVisitor subRefs(this, /*delta=*/-1);
698 subRefs.visitStatement(*stmt);
699}
700
701void ProgramUsage::remove(const ProgramElement& element) {
702 ProgramUsageVisitor subRefs(this, /*delta=*/-1);
703 subRefs.visitProgramElement(element);
Brian Osman2e25ff42020-10-15 10:32:04 -0400704}
705
Ethan Nicholas765d2fe2020-08-26 08:29:55 -0400706bool Analysis::StatementWritesToVariable(const Statement& stmt, const Variable& var) {
707 return VariableWriteVisitor(&var).visit(stmt);
708}
709
John Stilesb21fac22020-12-04 15:36:49 -0500710bool Analysis::IsAssignable(Expression& expr, AssignmentInfo* info, ErrorReporter* errors) {
John Stilesa976da72020-09-25 23:06:26 -0400711 TrivialErrorReporter trivialErrors;
John Stilesb21fac22020-12-04 15:36:49 -0500712 return IsAssignableVisitor{errors ? errors : &trivialErrors}.visit(expr, info);
John Stilesdce4d3e2020-09-25 14:35:13 -0400713}
714
John Stiles47c0a742021-02-09 09:30:35 -0500715void Analysis::UpdateRefKind(Expression* expr, VariableRefKind refKind) {
716 class RefKindWriter : public ProgramWriter {
717 public:
718 RefKindWriter(VariableReference::RefKind refKind) : fRefKind(refKind) {}
719
720 bool visitExpression(Expression& expr) override {
721 if (expr.is<VariableReference>()) {
722 expr.as<VariableReference>().setRefKind(fRefKind);
723 }
724 return INHERITED::visitExpression(expr);
725 }
726
727 private:
728 VariableReference::RefKind fRefKind;
729
730 using INHERITED = ProgramWriter;
731 };
732
733 RefKindWriter{refKind}.visitExpression(*expr);
734}
735
John Stiles516704b2021-02-26 15:01:57 -0500736bool Analysis::MakeAssignmentExpr(Expression* expr,
737 VariableReference::RefKind kind,
738 ErrorReporter* errors) {
739 Analysis::AssignmentInfo info;
740 if (!Analysis::IsAssignable(*expr, &info, errors)) {
741 return false;
742 }
743 if (!info.fAssignedVar) {
744 errors->error(expr->fOffset, "can't assign to expression '" + expr->description() + "'");
745 return false;
746 }
747 info.fAssignedVar->setRefKind(kind);
748 return true;
749}
750
John Stilesc30fbca2020-11-19 16:25:49 -0500751bool Analysis::IsTrivialExpression(const Expression& expr) {
752 return expr.is<IntLiteral>() ||
753 expr.is<FloatLiteral>() ||
754 expr.is<BoolLiteral>() ||
755 expr.is<VariableReference>() ||
756 (expr.is<Swizzle>() &&
757 IsTrivialExpression(*expr.as<Swizzle>().base())) ||
758 (expr.is<FieldAccess>() &&
759 IsTrivialExpression(*expr.as<FieldAccess>().base())) ||
John Stiles2938eea2021-04-01 18:58:25 -0400760 (expr.isAnyConstructor() &&
761 expr.asAnyConstructor().argumentSpan().size() == 1 &&
762 IsTrivialExpression(*expr.asAnyConstructor().argumentSpan().front())) ||
763 (expr.isAnyConstructor() &&
John Stilesc30fbca2020-11-19 16:25:49 -0500764 expr.isConstantOrUniform()) ||
765 (expr.is<IndexExpression>() &&
766 expr.as<IndexExpression>().index()->is<IntLiteral>() &&
767 IsTrivialExpression(*expr.as<IndexExpression>().base()));
768}
769
John Stiles5676c572021-03-08 17:10:52 -0500770bool Analysis::IsSameExpressionTree(const Expression& left, const Expression& right) {
John Stiles95d0bad2021-03-01 17:02:28 -0500771 if (left.kind() != right.kind() || left.type() != right.type()) {
772 return false;
773 }
774
John Stiles5676c572021-03-08 17:10:52 -0500775 // This isn't a fully exhaustive list of expressions by any stretch of the imagination; for
776 // instance, `x[y+1] = x[y+1]` isn't detected because we don't look at BinaryExpressions.
777 // Since this is intended to be used for optimization purposes, handling the common cases is
778 // sufficient.
John Stiles95d0bad2021-03-01 17:02:28 -0500779 switch (left.kind()) {
780 case Expression::Kind::kIntLiteral:
781 return left.as<IntLiteral>().value() == right.as<IntLiteral>().value();
782
John Stiles5676c572021-03-08 17:10:52 -0500783 case Expression::Kind::kFloatLiteral:
784 return left.as<FloatLiteral>().value() == right.as<FloatLiteral>().value();
785
786 case Expression::Kind::kBoolLiteral:
787 return left.as<BoolLiteral>().value() == right.as<BoolLiteral>().value();
788
John Stiles7384b372021-04-01 13:48:15 -0400789 case Expression::Kind::kConstructorArray:
John Stiles8cad6372021-04-07 12:31:13 -0400790 case Expression::Kind::kConstructorCompound:
791 case Expression::Kind::kConstructorCompoundCast:
John Stiles2938eea2021-04-01 18:58:25 -0400792 case Expression::Kind::kConstructorDiagonalMatrix:
John Stiles5abb9e12021-04-06 13:47:19 -0400793 case Expression::Kind::kConstructorMatrixResize:
John Stilesfd7252f2021-04-04 22:24:40 -0400794 case Expression::Kind::kConstructorScalarCast:
John Stilesd47330f2021-04-08 23:25:52 -0400795 case Expression::Kind::kConstructorStruct:
John Stiles268a73f2021-04-07 12:30:22 -0400796 case Expression::Kind::kConstructorSplat: {
John Stilesfd7252f2021-04-04 22:24:40 -0400797 if (left.kind() != right.kind()) {
798 return false;
799 }
John Stiles7384b372021-04-01 13:48:15 -0400800 const AnyConstructor& leftCtor = left.asAnyConstructor();
801 const AnyConstructor& rightCtor = right.asAnyConstructor();
802 const auto leftSpan = leftCtor.argumentSpan();
803 const auto rightSpan = rightCtor.argumentSpan();
804 if (leftSpan.size() != rightSpan.size()) {
John Stiles5676c572021-03-08 17:10:52 -0500805 return false;
806 }
John Stiles7384b372021-04-01 13:48:15 -0400807 for (size_t index = 0; index < leftSpan.size(); ++index) {
808 if (!IsSameExpressionTree(*leftSpan[index], *rightSpan[index])) {
John Stiles5676c572021-03-08 17:10:52 -0500809 return false;
810 }
811 }
812 return true;
813 }
John Stiles95d0bad2021-03-01 17:02:28 -0500814 case Expression::Kind::kFieldAccess:
815 return left.as<FieldAccess>().fieldIndex() == right.as<FieldAccess>().fieldIndex() &&
John Stiles5676c572021-03-08 17:10:52 -0500816 IsSameExpressionTree(*left.as<FieldAccess>().base(),
817 *right.as<FieldAccess>().base());
John Stiles95d0bad2021-03-01 17:02:28 -0500818
819 case Expression::Kind::kIndex:
John Stiles5676c572021-03-08 17:10:52 -0500820 return IsSameExpressionTree(*left.as<IndexExpression>().index(),
821 *right.as<IndexExpression>().index()) &&
822 IsSameExpressionTree(*left.as<IndexExpression>().base(),
823 *right.as<IndexExpression>().base());
John Stiles95d0bad2021-03-01 17:02:28 -0500824
825 case Expression::Kind::kSwizzle:
826 return left.as<Swizzle>().components() == right.as<Swizzle>().components() &&
John Stiles5676c572021-03-08 17:10:52 -0500827 IsSameExpressionTree(*left.as<Swizzle>().base(), *right.as<Swizzle>().base());
John Stiles95d0bad2021-03-01 17:02:28 -0500828
829 case Expression::Kind::kVariableReference:
830 return left.as<VariableReference>().variable() ==
831 right.as<VariableReference>().variable();
832
833 default:
834 return false;
835 }
836}
837
John Stilesd80cef62021-03-29 11:22:43 -0400838static bool get_constant_value(const Expression& expr, double* val) {
John Stiles21a50ec2021-04-06 14:49:36 -0400839 const Expression* valExpr = expr.getConstantSubexpression(0);
840 if (!valExpr) {
John Stilesd80cef62021-03-29 11:22:43 -0400841 return false;
842 }
John Stiles21a50ec2021-04-06 14:49:36 -0400843 if (valExpr->is<IntLiteral>()) {
844 *val = static_cast<double>(valExpr->as<IntLiteral>().value());
845 return true;
John Stilesd80cef62021-03-29 11:22:43 -0400846 }
John Stiles21a50ec2021-04-06 14:49:36 -0400847 if (valExpr->is<FloatLiteral>()) {
848 *val = static_cast<double>(valExpr->as<FloatLiteral>().value());
849 return true;
850 }
851 SkDEBUGFAILF("unexpected constant type (%s)", expr.type().description().c_str());
852 return false;
John Stilesd80cef62021-03-29 11:22:43 -0400853}
854
John Stiles232b4ce2021-03-01 22:14:22 -0500855static const char* invalid_for_ES2(int offset,
856 const Statement* loopInitializer,
857 const Expression* loopTest,
858 const Expression* loopNext,
859 const Statement* loopStatement,
Brian Osman77ba8102021-01-12 17:15:30 -0500860 Analysis::UnrollableLoopInfo& loopInfo) {
Brian Osman77ba8102021-01-12 17:15:30 -0500861 //
862 // init_declaration has the form: type_specifier identifier = constant_expression
863 //
John Stiles232b4ce2021-03-01 22:14:22 -0500864 if (!loopInitializer) {
Brian Osman77ba8102021-01-12 17:15:30 -0500865 return "missing init declaration";
866 }
John Stiles232b4ce2021-03-01 22:14:22 -0500867 if (!loopInitializer->is<VarDeclaration>()) {
Brian Osman77ba8102021-01-12 17:15:30 -0500868 return "invalid init declaration";
869 }
John Stiles232b4ce2021-03-01 22:14:22 -0500870 const VarDeclaration& initDecl = loopInitializer->as<VarDeclaration>();
Brian Osman6c7910e2021-01-14 09:50:52 -0500871 if (!initDecl.baseType().isNumber()) {
Brian Osman77ba8102021-01-12 17:15:30 -0500872 return "invalid type for loop index";
873 }
874 if (initDecl.arraySize() != 0) {
875 return "invalid type for loop index";
876 }
877 if (!initDecl.value()) {
878 return "missing loop index initializer";
879 }
John Stilesd80cef62021-03-29 11:22:43 -0400880 if (!get_constant_value(*initDecl.value(), &loopInfo.fStart)) {
Brian Osman77ba8102021-01-12 17:15:30 -0500881 return "loop index initializer must be a constant expression";
882 }
883
884 loopInfo.fIndex = &initDecl.var();
885
886 auto is_loop_index = [&](const std::unique_ptr<Expression>& expr) {
887 return expr->is<VariableReference>() &&
888 expr->as<VariableReference>().variable() == loopInfo.fIndex;
889 };
890
891 //
892 // condition has the form: loop_index relational_operator constant_expression
893 //
John Stiles232b4ce2021-03-01 22:14:22 -0500894 if (!loopTest) {
Brian Osman77ba8102021-01-12 17:15:30 -0500895 return "missing condition";
896 }
John Stiles232b4ce2021-03-01 22:14:22 -0500897 if (!loopTest->is<BinaryExpression>()) {
Brian Osman77ba8102021-01-12 17:15:30 -0500898 return "invalid condition";
899 }
John Stiles232b4ce2021-03-01 22:14:22 -0500900 const BinaryExpression& cond = loopTest->as<BinaryExpression>();
Brian Osman77ba8102021-01-12 17:15:30 -0500901 if (!is_loop_index(cond.left())) {
902 return "expected loop index on left hand side of condition";
903 }
904 // relational_operator is one of: > >= < <= == or !=
John Stiles45990502021-02-16 10:55:27 -0500905 switch (cond.getOperator().kind()) {
Brian Osman77ba8102021-01-12 17:15:30 -0500906 case Token::Kind::TK_GT:
907 case Token::Kind::TK_GTEQ:
908 case Token::Kind::TK_LT:
909 case Token::Kind::TK_LTEQ:
910 case Token::Kind::TK_EQEQ:
911 case Token::Kind::TK_NEQ:
912 break;
913 default:
914 return "invalid relational operator";
915 }
916 double loopEnd = 0;
John Stilesd80cef62021-03-29 11:22:43 -0400917 if (!get_constant_value(*cond.right(), &loopEnd)) {
Brian Osman77ba8102021-01-12 17:15:30 -0500918 return "loop index must be compared with a constant expression";
919 }
920
921 //
922 // expression has one of the following forms:
923 // loop_index++
924 // loop_index--
925 // loop_index += constant_expression
926 // loop_index -= constant_expression
927 // The spec doesn't mention prefix increment and decrement, but there is some consensus that
928 // it's an oversight, so we allow those as well.
929 //
John Stiles232b4ce2021-03-01 22:14:22 -0500930 if (!loopNext) {
Brian Osman77ba8102021-01-12 17:15:30 -0500931 return "missing loop expression";
932 }
John Stiles232b4ce2021-03-01 22:14:22 -0500933 switch (loopNext->kind()) {
Brian Osman77ba8102021-01-12 17:15:30 -0500934 case Expression::Kind::kBinary: {
John Stiles232b4ce2021-03-01 22:14:22 -0500935 const BinaryExpression& next = loopNext->as<BinaryExpression>();
Brian Osman77ba8102021-01-12 17:15:30 -0500936 if (!is_loop_index(next.left())) {
937 return "expected loop index in loop expression";
938 }
John Stilesd80cef62021-03-29 11:22:43 -0400939 if (!get_constant_value(*next.right(), &loopInfo.fDelta)) {
Brian Osman77ba8102021-01-12 17:15:30 -0500940 return "loop index must be modified by a constant expression";
941 }
John Stiles45990502021-02-16 10:55:27 -0500942 switch (next.getOperator().kind()) {
Brian Osman77ba8102021-01-12 17:15:30 -0500943 case Token::Kind::TK_PLUSEQ: break;
944 case Token::Kind::TK_MINUSEQ: loopInfo.fDelta = -loopInfo.fDelta; break;
945 default:
946 return "invalid operator in loop expression";
947 }
948 } break;
949 case Expression::Kind::kPrefix: {
John Stiles232b4ce2021-03-01 22:14:22 -0500950 const PrefixExpression& next = loopNext->as<PrefixExpression>();
Brian Osman77ba8102021-01-12 17:15:30 -0500951 if (!is_loop_index(next.operand())) {
952 return "expected loop index in loop expression";
953 }
John Stiles45990502021-02-16 10:55:27 -0500954 switch (next.getOperator().kind()) {
Brian Osman77ba8102021-01-12 17:15:30 -0500955 case Token::Kind::TK_PLUSPLUS: loopInfo.fDelta = 1; break;
956 case Token::Kind::TK_MINUSMINUS: loopInfo.fDelta = -1; break;
957 default:
958 return "invalid operator in loop expression";
959 }
960 } break;
961 case Expression::Kind::kPostfix: {
John Stiles232b4ce2021-03-01 22:14:22 -0500962 const PostfixExpression& next = loopNext->as<PostfixExpression>();
Brian Osman77ba8102021-01-12 17:15:30 -0500963 if (!is_loop_index(next.operand())) {
964 return "expected loop index in loop expression";
965 }
John Stiles45990502021-02-16 10:55:27 -0500966 switch (next.getOperator().kind()) {
Brian Osman77ba8102021-01-12 17:15:30 -0500967 case Token::Kind::TK_PLUSPLUS: loopInfo.fDelta = 1; break;
968 case Token::Kind::TK_MINUSMINUS: loopInfo.fDelta = -1; break;
969 default:
970 return "invalid operator in loop expression";
971 }
972 } break;
973 default:
974 return "invalid loop expression";
975 }
976
977 //
978 // Within the body of the loop, the loop index is not statically assigned to, nor is it used as
979 // argument to a function 'out' or 'inout' parameter.
980 //
John Stiles232b4ce2021-03-01 22:14:22 -0500981 if (Analysis::StatementWritesToVariable(*loopStatement, initDecl.var())) {
Brian Osman77ba8102021-01-12 17:15:30 -0500982 return "loop index must not be modified within body of the loop";
983 }
984
985 // Finally, compute the iteration count, based on the bounds, and the termination operator.
986 constexpr int kMaxUnrollableLoopLength = 128;
987 loopInfo.fCount = 0;
988
989 double val = loopInfo.fStart;
990 auto evalCond = [&]() {
John Stiles45990502021-02-16 10:55:27 -0500991 switch (cond.getOperator().kind()) {
Brian Osman77ba8102021-01-12 17:15:30 -0500992 case Token::Kind::TK_GT: return val > loopEnd;
993 case Token::Kind::TK_GTEQ: return val >= loopEnd;
994 case Token::Kind::TK_LT: return val < loopEnd;
995 case Token::Kind::TK_LTEQ: return val <= loopEnd;
996 case Token::Kind::TK_EQEQ: return val == loopEnd;
997 case Token::Kind::TK_NEQ: return val != loopEnd;
998 default: SkUNREACHABLE;
999 }
1000 };
1001
1002 for (loopInfo.fCount = 0; loopInfo.fCount <= kMaxUnrollableLoopLength; ++loopInfo.fCount) {
1003 if (!evalCond()) {
1004 break;
1005 }
1006 val += loopInfo.fDelta;
1007 }
1008
1009 if (loopInfo.fCount > kMaxUnrollableLoopLength) {
1010 return "loop must guarantee termination in fewer iterations";
1011 }
1012
1013 return nullptr; // All checks pass
1014}
1015
John Stiles232b4ce2021-03-01 22:14:22 -05001016bool Analysis::ForLoopIsValidForES2(int offset,
1017 const Statement* loopInitializer,
1018 const Expression* loopTest,
1019 const Expression* loopNext,
1020 const Statement* loopStatement,
Brian Osman77ba8102021-01-12 17:15:30 -05001021 Analysis::UnrollableLoopInfo* outLoopInfo,
1022 ErrorReporter* errors) {
1023 UnrollableLoopInfo ignored,
1024 *loopInfo = outLoopInfo ? outLoopInfo : &ignored;
John Stiles232b4ce2021-03-01 22:14:22 -05001025 if (const char* msg = invalid_for_ES2(
1026 offset, loopInitializer, loopTest, loopNext, loopStatement, *loopInfo)) {
Brian Osman77ba8102021-01-12 17:15:30 -05001027 if (errors) {
John Stiles232b4ce2021-03-01 22:14:22 -05001028 errors->error(offset, msg);
Brian Osman77ba8102021-01-12 17:15:30 -05001029 }
1030 return false;
1031 }
1032 return true;
1033}
1034
Brian Osman7b361492021-02-25 11:25:30 -05001035// Checks for ES2 constant-expression rules, and (optionally) constant-index-expression rules
1036// (if loopIndices is non-nullptr)
1037class ConstantExpressionVisitor : public ProgramVisitor {
Brian Osmanea485e52021-01-15 13:20:32 -05001038public:
Brian Osman7b361492021-02-25 11:25:30 -05001039 ConstantExpressionVisitor(const std::set<const Variable*>* loopIndices)
Brian Osmanea485e52021-01-15 13:20:32 -05001040 : fLoopIndices(loopIndices) {}
1041
1042 bool visitExpression(const Expression& e) override {
1043 // A constant-(index)-expression is one of...
1044 switch (e.kind()) {
1045 // ... a literal value
1046 case Expression::Kind::kBoolLiteral:
1047 case Expression::Kind::kIntLiteral:
1048 case Expression::Kind::kFloatLiteral:
1049 return false;
1050
John Stiles532138c2021-03-04 16:29:22 -05001051 // ... settings can appear in fragment processors; they will resolve when compiled
1052 case Expression::Kind::kSetting:
1053 return false;
1054
Brian Osman7b361492021-02-25 11:25:30 -05001055 // ... a global or local variable qualified as 'const', excluding function parameters.
1056 // ... loop indices as defined in section 4. [constant-index-expression]
1057 case Expression::Kind::kVariableReference: {
1058 const Variable* v = e.as<VariableReference>().variable();
1059 if ((v->storage() == Variable::Storage::kGlobal ||
1060 v->storage() == Variable::Storage::kLocal) &&
1061 (v->modifiers().fFlags & Modifiers::kConst_Flag)) {
1062 return false;
1063 }
1064 return !fLoopIndices || fLoopIndices->find(v) == fLoopIndices->end();
1065 }
Brian Osmanea485e52021-01-15 13:20:32 -05001066
1067 // ... expressions composed of both of the above
1068 case Expression::Kind::kBinary:
John Stiles7384b372021-04-01 13:48:15 -04001069 case Expression::Kind::kConstructorArray:
John Stiles8cad6372021-04-07 12:31:13 -04001070 case Expression::Kind::kConstructorCompound:
1071 case Expression::Kind::kConstructorCompoundCast:
John Stilese1182782021-03-30 22:09:37 -04001072 case Expression::Kind::kConstructorDiagonalMatrix:
John Stiles5abb9e12021-04-06 13:47:19 -04001073 case Expression::Kind::kConstructorMatrixResize:
John Stilesfd7252f2021-04-04 22:24:40 -04001074 case Expression::Kind::kConstructorScalarCast:
John Stiles2938eea2021-04-01 18:58:25 -04001075 case Expression::Kind::kConstructorSplat:
John Stilesd47330f2021-04-08 23:25:52 -04001076 case Expression::Kind::kConstructorStruct:
Brian Osmanea485e52021-01-15 13:20:32 -05001077 case Expression::Kind::kFieldAccess:
1078 case Expression::Kind::kIndex:
1079 case Expression::Kind::kPrefix:
1080 case Expression::Kind::kPostfix:
1081 case Expression::Kind::kSwizzle:
1082 case Expression::Kind::kTernary:
1083 return INHERITED::visitExpression(e);
1084
Brian Osman7b361492021-02-25 11:25:30 -05001085 // These are completely disallowed in SkSL constant-(index)-expressions. GLSL allows
Brian Osmanea485e52021-01-15 13:20:32 -05001086 // calls to built-in functions where the arguments are all constant-expressions, but
1087 // we don't guarantee that behavior. (skbug.com/10835)
1088 case Expression::Kind::kExternalFunctionCall:
1089 case Expression::Kind::kFunctionCall:
1090 return true;
1091
Ethan Nicholas549c6b82021-06-25 12:31:44 -04001092 case Expression::Kind::kPoison:
1093 return true;
1094
Brian Osmanea485e52021-01-15 13:20:32 -05001095 // These should never appear in final IR
Brian Osmanea485e52021-01-15 13:20:32 -05001096 case Expression::Kind::kExternalFunctionReference:
1097 case Expression::Kind::kFunctionReference:
Brian Osmanea485e52021-01-15 13:20:32 -05001098 case Expression::Kind::kTypeReference:
1099 default:
1100 SkDEBUGFAIL("Unexpected expression type");
1101 return true;
1102 }
1103 }
1104
1105private:
1106 const std::set<const Variable*>* fLoopIndices;
1107 using INHERITED = ProgramVisitor;
1108};
1109
1110class ES2IndexingVisitor : public ProgramVisitor {
1111public:
1112 ES2IndexingVisitor(ErrorReporter& errors) : fErrors(errors) {}
1113
1114 bool visitStatement(const Statement& s) override {
1115 if (s.is<ForStatement>()) {
1116 const ForStatement& f = s.as<ForStatement>();
1117 SkASSERT(f.initializer() && f.initializer()->is<VarDeclaration>());
1118 const Variable* var = &f.initializer()->as<VarDeclaration>().var();
1119 auto [iter, inserted] = fLoopIndices.insert(var);
1120 SkASSERT(inserted);
1121 bool result = this->visitStatement(*f.statement());
1122 fLoopIndices.erase(iter);
1123 return result;
1124 }
1125 return INHERITED::visitStatement(s);
1126 }
1127
1128 bool visitExpression(const Expression& e) override {
1129 if (e.is<IndexExpression>()) {
1130 const IndexExpression& i = e.as<IndexExpression>();
Brian Osman7b361492021-02-25 11:25:30 -05001131 ConstantExpressionVisitor indexerInvalid(&fLoopIndices);
Brian Osmanea485e52021-01-15 13:20:32 -05001132 if (indexerInvalid.visitExpression(*i.index())) {
1133 fErrors.error(i.fOffset, "index expression must be constant");
1134 return true;
1135 }
1136 }
1137 return INHERITED::visitExpression(e);
1138 }
1139
1140 using ProgramVisitor::visitProgramElement;
1141
1142private:
1143 ErrorReporter& fErrors;
1144 std::set<const Variable*> fLoopIndices;
1145 using INHERITED = ProgramVisitor;
1146};
1147
1148
1149void Analysis::ValidateIndexingForES2(const ProgramElement& pe, ErrorReporter& errors) {
1150 ES2IndexingVisitor visitor(errors);
1151 visitor.visitProgramElement(pe);
1152}
1153
Brian Osman7b361492021-02-25 11:25:30 -05001154bool Analysis::IsConstantExpression(const Expression& expr) {
1155 ConstantExpressionVisitor visitor(/*loopIndices=*/nullptr);
1156 return !visitor.visitExpression(expr);
1157}
1158
John Stiles958f4b52021-03-17 16:39:49 -04001159bool Analysis::CanExitWithoutReturningValue(const FunctionDeclaration& funcDecl,
1160 const Statement& body) {
1161 if (funcDecl.returnType().isVoid()) {
1162 return false;
1163 }
John Stilesb3dcbb12021-03-04 16:00:20 -05001164 ReturnsOnAllPathsVisitor visitor;
John Stiles958f4b52021-03-17 16:39:49 -04001165 visitor.visitStatement(body);
John Stilesb3dcbb12021-03-04 16:00:20 -05001166 return !visitor.fFoundReturn;
1167}
1168
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001169////////////////////////////////////////////////////////////////////////////////
1170// ProgramVisitor
1171
Brian Osman133724c2020-10-28 14:14:39 -04001172bool ProgramVisitor::visit(const Program& program) {
1173 for (const ProgramElement* pe : program.elements()) {
Brian Osman1179fcf2020-10-08 16:04:40 -04001174 if (this->visitProgramElement(*pe)) {
John Stiles933abe32020-08-28 11:58:40 -04001175 return true;
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001176 }
1177 }
John Stiles933abe32020-08-28 11:58:40 -04001178 return false;
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001179}
1180
John Stiles48b25582021-03-11 14:26:42 -05001181template <typename T> bool TProgramVisitor<T>::visitExpression(typename T::Expression& e) {
John Stiles70b82422020-09-30 10:55:12 -04001182 switch (e.kind()) {
Ethan Nicholase6592142020-09-08 10:22:09 -04001183 case Expression::Kind::kBoolLiteral:
Brian Osmanbe0b3b72021-01-06 14:27:35 -05001184 case Expression::Kind::kExternalFunctionReference:
Ethan Nicholase6592142020-09-08 10:22:09 -04001185 case Expression::Kind::kFloatLiteral:
1186 case Expression::Kind::kFunctionReference:
1187 case Expression::Kind::kIntLiteral:
Ethan Nicholas549c6b82021-06-25 12:31:44 -04001188 case Expression::Kind::kPoison:
Ethan Nicholase6592142020-09-08 10:22:09 -04001189 case Expression::Kind::kSetting:
1190 case Expression::Kind::kTypeReference:
1191 case Expression::Kind::kVariableReference:
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001192 // Leaf expressions return false
1193 return false;
John Stiles70b82422020-09-30 10:55:12 -04001194
Ethan Nicholase6592142020-09-08 10:22:09 -04001195 case Expression::Kind::kBinary: {
John Stiles70b82422020-09-30 10:55:12 -04001196 auto& b = e.template as<BinaryExpression>();
John Stiles48b25582021-03-11 14:26:42 -05001197 return (b.left() && this->visitExpressionPtr(b.left())) ||
1198 (b.right() && this->visitExpressionPtr(b.right()));
John Stiles70b82422020-09-30 10:55:12 -04001199 }
John Stiles7384b372021-04-01 13:48:15 -04001200 case Expression::Kind::kConstructorArray:
John Stiles8cad6372021-04-07 12:31:13 -04001201 case Expression::Kind::kConstructorCompound:
1202 case Expression::Kind::kConstructorCompoundCast:
John Stiles2938eea2021-04-01 18:58:25 -04001203 case Expression::Kind::kConstructorDiagonalMatrix:
John Stiles5abb9e12021-04-06 13:47:19 -04001204 case Expression::Kind::kConstructorMatrixResize:
John Stilesfd7252f2021-04-04 22:24:40 -04001205 case Expression::Kind::kConstructorScalarCast:
John Stilesd47330f2021-04-08 23:25:52 -04001206 case Expression::Kind::kConstructorSplat:
1207 case Expression::Kind::kConstructorStruct: {
John Stiles7384b372021-04-01 13:48:15 -04001208 auto& c = e.asAnyConstructor();
1209 for (auto& arg : c.argumentSpan()) {
John Stiles48b25582021-03-11 14:26:42 -05001210 if (this->visitExpressionPtr(arg)) { return true; }
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001211 }
John Stiles70b82422020-09-30 10:55:12 -04001212 return false;
1213 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001214 case Expression::Kind::kExternalFunctionCall: {
John Stiles70b82422020-09-30 10:55:12 -04001215 auto& c = e.template as<ExternalFunctionCall>();
Ethan Nicholas6e86ec92020-09-30 14:29:56 -04001216 for (auto& arg : c.arguments()) {
John Stiles48b25582021-03-11 14:26:42 -05001217 if (this->visitExpressionPtr(arg)) { return true; }
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001218 }
John Stiles70b82422020-09-30 10:55:12 -04001219 return false;
1220 }
John Stilesd7ab4502020-09-24 22:41:00 -04001221 case Expression::Kind::kFieldAccess:
John Stiles48b25582021-03-11 14:26:42 -05001222 return this->visitExpressionPtr(e.template as<FieldAccess>().base());
John Stiles70b82422020-09-30 10:55:12 -04001223
Ethan Nicholase6592142020-09-08 10:22:09 -04001224 case Expression::Kind::kFunctionCall: {
John Stiles70b82422020-09-30 10:55:12 -04001225 auto& c = e.template as<FunctionCall>();
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001226 for (auto& arg : c.arguments()) {
John Stiles48b25582021-03-11 14:26:42 -05001227 if (arg && this->visitExpressionPtr(arg)) { return true; }
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001228 }
John Stiles70b82422020-09-30 10:55:12 -04001229 return false;
1230 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001231 case Expression::Kind::kIndex: {
John Stiles70b82422020-09-30 10:55:12 -04001232 auto& i = e.template as<IndexExpression>();
John Stiles48b25582021-03-11 14:26:42 -05001233 return this->visitExpressionPtr(i.base()) || this->visitExpressionPtr(i.index());
John Stiles70b82422020-09-30 10:55:12 -04001234 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001235 case Expression::Kind::kPostfix:
John Stiles48b25582021-03-11 14:26:42 -05001236 return this->visitExpressionPtr(e.template as<PostfixExpression>().operand());
John Stiles70b82422020-09-30 10:55:12 -04001237
Ethan Nicholase6592142020-09-08 10:22:09 -04001238 case Expression::Kind::kPrefix:
John Stiles48b25582021-03-11 14:26:42 -05001239 return this->visitExpressionPtr(e.template as<PrefixExpression>().operand());
John Stiles70b82422020-09-30 10:55:12 -04001240
Brian Osman010ce6a2020-10-19 16:34:10 -04001241 case Expression::Kind::kSwizzle: {
1242 auto& s = e.template as<Swizzle>();
John Stiles48b25582021-03-11 14:26:42 -05001243 return s.base() && this->visitExpressionPtr(s.base());
Brian Osman010ce6a2020-10-19 16:34:10 -04001244 }
John Stiles70b82422020-09-30 10:55:12 -04001245
Ethan Nicholase6592142020-09-08 10:22:09 -04001246 case Expression::Kind::kTernary: {
John Stiles70b82422020-09-30 10:55:12 -04001247 auto& t = e.template as<TernaryExpression>();
John Stiles48b25582021-03-11 14:26:42 -05001248 return this->visitExpressionPtr(t.test()) ||
1249 (t.ifTrue() && this->visitExpressionPtr(t.ifTrue())) ||
1250 (t.ifFalse() && this->visitExpressionPtr(t.ifFalse()));
John Stiles70b82422020-09-30 10:55:12 -04001251 }
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001252 default:
1253 SkUNREACHABLE;
1254 }
1255}
1256
John Stiles48b25582021-03-11 14:26:42 -05001257template <typename T> bool TProgramVisitor<T>::visitStatement(typename T::Statement& s) {
John Stiles70b82422020-09-30 10:55:12 -04001258 switch (s.kind()) {
Ethan Nicholase6592142020-09-08 10:22:09 -04001259 case Statement::Kind::kBreak:
1260 case Statement::Kind::kContinue:
1261 case Statement::Kind::kDiscard:
John Stiles98c1f822020-09-09 14:18:53 -04001262 case Statement::Kind::kInlineMarker:
Ethan Nicholase6592142020-09-08 10:22:09 -04001263 case Statement::Kind::kNop:
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001264 // Leaf statements just return false
1265 return false;
John Stiles70b82422020-09-30 10:55:12 -04001266
Ethan Nicholase6592142020-09-08 10:22:09 -04001267 case Statement::Kind::kBlock:
John Stiles70b82422020-09-30 10:55:12 -04001268 for (auto& stmt : s.template as<Block>().children()) {
John Stiles48b25582021-03-11 14:26:42 -05001269 if (stmt && this->visitStatementPtr(stmt)) {
Ethan Nicholas7bd60432020-09-25 14:31:59 -04001270 return true;
1271 }
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001272 }
1273 return false;
John Stiles70b82422020-09-30 10:55:12 -04001274
John Stilesa0e56e32021-03-03 13:14:37 -05001275 case Statement::Kind::kSwitchCase: {
1276 auto& sc = s.template as<SwitchCase>();
John Stiles48b25582021-03-11 14:26:42 -05001277 if (sc.value() && this->visitExpressionPtr(sc.value())) {
John Stilesa0e56e32021-03-03 13:14:37 -05001278 return true;
1279 }
John Stiles48b25582021-03-11 14:26:42 -05001280 return this->visitStatementPtr(sc.statement());
John Stilesa0e56e32021-03-03 13:14:37 -05001281 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001282 case Statement::Kind::kDo: {
John Stiles70b82422020-09-30 10:55:12 -04001283 auto& d = s.template as<DoStatement>();
John Stiles48b25582021-03-11 14:26:42 -05001284 return this->visitExpressionPtr(d.test()) || this->visitStatementPtr(d.statement());
John Stiles70b82422020-09-30 10:55:12 -04001285 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001286 case Statement::Kind::kExpression:
John Stiles48b25582021-03-11 14:26:42 -05001287 return this->visitExpressionPtr(s.template as<ExpressionStatement>().expression());
John Stiles70b82422020-09-30 10:55:12 -04001288
Ethan Nicholase6592142020-09-08 10:22:09 -04001289 case Statement::Kind::kFor: {
John Stiles70b82422020-09-30 10:55:12 -04001290 auto& f = s.template as<ForStatement>();
John Stiles48b25582021-03-11 14:26:42 -05001291 return (f.initializer() && this->visitStatementPtr(f.initializer())) ||
1292 (f.test() && this->visitExpressionPtr(f.test())) ||
1293 (f.next() && this->visitExpressionPtr(f.next())) ||
1294 this->visitStatementPtr(f.statement());
John Stiles70b82422020-09-30 10:55:12 -04001295 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001296 case Statement::Kind::kIf: {
John Stiles70b82422020-09-30 10:55:12 -04001297 auto& i = s.template as<IfStatement>();
John Stiles48b25582021-03-11 14:26:42 -05001298 return (i.test() && this->visitExpressionPtr(i.test())) ||
1299 (i.ifTrue() && this->visitStatementPtr(i.ifTrue())) ||
1300 (i.ifFalse() && this->visitStatementPtr(i.ifFalse()));
John Stiles70b82422020-09-30 10:55:12 -04001301 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001302 case Statement::Kind::kReturn: {
John Stiles70b82422020-09-30 10:55:12 -04001303 auto& r = s.template as<ReturnStatement>();
John Stiles48b25582021-03-11 14:26:42 -05001304 return r.expression() && this->visitExpressionPtr(r.expression());
John Stiles70b82422020-09-30 10:55:12 -04001305 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001306 case Statement::Kind::kSwitch: {
John Stiles70b82422020-09-30 10:55:12 -04001307 auto& sw = s.template as<SwitchStatement>();
John Stiles48b25582021-03-11 14:26:42 -05001308 if (this->visitExpressionPtr(sw.value())) {
John Stiles70b82422020-09-30 10:55:12 -04001309 return true;
1310 }
John Stiles48b25582021-03-11 14:26:42 -05001311 for (auto& c : sw.cases()) {
1312 if (this->visitStatementPtr(c)) {
John Stiles70b82422020-09-30 10:55:12 -04001313 return true;
1314 }
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001315 }
John Stiles70b82422020-09-30 10:55:12 -04001316 return false;
1317 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001318 case Statement::Kind::kVarDeclaration: {
John Stiles70b82422020-09-30 10:55:12 -04001319 auto& v = s.template as<VarDeclaration>();
John Stiles48b25582021-03-11 14:26:42 -05001320 return v.value() && this->visitExpressionPtr(v.value());
John Stiles70b82422020-09-30 10:55:12 -04001321 }
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001322 default:
1323 SkUNREACHABLE;
1324 }
1325}
1326
John Stiles48b25582021-03-11 14:26:42 -05001327template <typename T> bool TProgramVisitor<T>::visitProgramElement(typename T::ProgramElement& pe) {
John Stiles70b82422020-09-30 10:55:12 -04001328 switch (pe.kind()) {
Ethan Nicholase6592142020-09-08 10:22:09 -04001329 case ProgramElement::Kind::kEnum:
1330 case ProgramElement::Kind::kExtension:
John Stiles569249b2020-11-03 12:18:22 -05001331 case ProgramElement::Kind::kFunctionPrototype:
John Stilesd39aec02020-12-03 10:42:26 -05001332 case ProgramElement::Kind::kInterfaceBlock:
Ethan Nicholase6592142020-09-08 10:22:09 -04001333 case ProgramElement::Kind::kModifiers:
1334 case ProgramElement::Kind::kSection:
John Stilesdc75a972020-11-25 16:24:55 -05001335 case ProgramElement::Kind::kStructDefinition:
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001336 // Leaf program elements just return false by default
1337 return false;
John Stiles70b82422020-09-30 10:55:12 -04001338
Ethan Nicholase6592142020-09-08 10:22:09 -04001339 case ProgramElement::Kind::kFunction:
John Stiles48b25582021-03-11 14:26:42 -05001340 return this->visitStatementPtr(pe.template as<FunctionDefinition>().body());
John Stiles70b82422020-09-30 10:55:12 -04001341
Brian Osmanc0213602020-10-06 14:43:32 -04001342 case ProgramElement::Kind::kGlobalVar:
John Stiles48b25582021-03-11 14:26:42 -05001343 return this->visitStatementPtr(pe.template as<GlobalVarDeclaration>().declaration());
John Stiles70b82422020-09-30 10:55:12 -04001344
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001345 default:
1346 SkUNREACHABLE;
1347 }
1348}
1349
John Stiles48b25582021-03-11 14:26:42 -05001350template class TProgramVisitor<ProgramVisitorTypes>;
1351template class TProgramVisitor<ProgramWriterTypes>;
John Stiles70b82422020-09-30 10:55:12 -04001352
John Stilesa6841be2020-08-06 14:11:56 -04001353} // namespace SkSL