blob: 8a7d5d7600d25bab9bf5a18c461d1cbc08183211 [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
John Stiles106e0cd2021-09-07 11:43:51 -040010#include "include/private/SkFloatingPoint.h"
Ethan Nicholasdaed2592021-03-04 14:30:25 -050011#include "include/private/SkSLModifiers.h"
Ethan Nicholas24c17722021-03-09 13:10:59 -050012#include "include/private/SkSLProgramElement.h"
Brian Osman1298bc42020-06-30 13:39:35 -040013#include "include/private/SkSLSampleUsage.h"
Ethan Nicholas24c17722021-03-09 13:10:59 -050014#include "include/private/SkSLStatement.h"
Ethan Nicholas4a5e22a2021-08-13 17:29:51 -040015#include "include/sksl/SkSLErrorReporter.h"
John Stiles61e5e202021-09-02 09:56:31 -040016#include "src/core/SkSafeMath.h"
Brian Osman00185012021-02-04 16:07:11 -050017#include "src/sksl/SkSLCompiler.h"
Brian Osman448b2d52021-09-23 11:36:15 -040018#include "src/sksl/SkSLConstantFolder.h"
Michael Ludwig8f3a8362020-06-29 17:27:00 -040019#include "src/sksl/ir/SkSLExpression.h"
20#include "src/sksl/ir/SkSLProgram.h"
Michael Ludwig8f3a8362020-06-29 17:27:00 -040021
22// ProgramElements
Michael Ludwig8f3a8362020-06-29 17:27:00 -040023#include "src/sksl/ir/SkSLExtension.h"
24#include "src/sksl/ir/SkSLFunctionDefinition.h"
25#include "src/sksl/ir/SkSLInterfaceBlock.h"
Michael Ludwig8f3a8362020-06-29 17:27:00 -040026#include "src/sksl/ir/SkSLVarDeclarations.h"
27
28// Statements
29#include "src/sksl/ir/SkSLBlock.h"
30#include "src/sksl/ir/SkSLBreakStatement.h"
31#include "src/sksl/ir/SkSLContinueStatement.h"
32#include "src/sksl/ir/SkSLDiscardStatement.h"
33#include "src/sksl/ir/SkSLDoStatement.h"
34#include "src/sksl/ir/SkSLExpressionStatement.h"
35#include "src/sksl/ir/SkSLForStatement.h"
36#include "src/sksl/ir/SkSLIfStatement.h"
37#include "src/sksl/ir/SkSLNop.h"
38#include "src/sksl/ir/SkSLReturnStatement.h"
39#include "src/sksl/ir/SkSLSwitchStatement.h"
Michael Ludwig8f3a8362020-06-29 17:27:00 -040040
41// Expressions
42#include "src/sksl/ir/SkSLBinaryExpression.h"
Brian Osmaneb0f29d2021-08-04 11:34:16 -040043#include "src/sksl/ir/SkSLChildCall.h"
Michael Ludwig8f3a8362020-06-29 17:27:00 -040044#include "src/sksl/ir/SkSLConstructor.h"
John Stilese1182782021-03-30 22:09:37 -040045#include "src/sksl/ir/SkSLConstructorDiagonalMatrix.h"
John Stiles5abb9e12021-04-06 13:47:19 -040046#include "src/sksl/ir/SkSLConstructorMatrixResize.h"
Michael Ludwig8f3a8362020-06-29 17:27:00 -040047#include "src/sksl/ir/SkSLExternalFunctionCall.h"
Brian Osmanbe0b3b72021-01-06 14:27:35 -050048#include "src/sksl/ir/SkSLExternalFunctionReference.h"
Michael Ludwig8f3a8362020-06-29 17:27:00 -040049#include "src/sksl/ir/SkSLFieldAccess.h"
Michael Ludwig8f3a8362020-06-29 17:27:00 -040050#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"
John Stiles7591d4b2021-09-13 13:32:06 -040054#include "src/sksl/ir/SkSLLiteral.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
John Stiles49b1a422021-09-22 09:35:39 -040063#include <stack>
64
Michael Ludwig8f3a8362020-06-29 17:27:00 -040065namespace SkSL {
66
67namespace {
68
Brian Osmaneb0f29d2021-08-04 11:34:16 -040069// Visitor that determines the merged SampleUsage for a given child in the program.
Brian Osman1298bc42020-06-30 13:39:35 -040070class MergeSampleUsageVisitor : public ProgramVisitor {
Michael Ludwig8f3a8362020-06-29 17:27:00 -040071public:
Brian Osmaneb0f29d2021-08-04 11:34:16 -040072 MergeSampleUsageVisitor(const Context& context,
73 const Variable& child,
74 bool writesToSampleCoords)
75 : fContext(context), fChild(child), fWritesToSampleCoords(writesToSampleCoords) {}
Michael Ludwig8f3a8362020-06-29 17:27:00 -040076
Brian Osman1298bc42020-06-30 13:39:35 -040077 SampleUsage visit(const Program& program) {
78 fUsage = SampleUsage(); // reset to none
John Stilesd7ab4502020-09-24 22:41:00 -040079 INHERITED::visit(program);
Brian Osman1298bc42020-06-30 13:39:35 -040080 return fUsage;
Michael Ludwig8f3a8362020-06-29 17:27:00 -040081 }
82
Brian Osman8cdf28f2021-05-24 09:52:39 -040083 int elidedSampleCoordCount() const { return fElidedSampleCoordCount; }
84
Michael Ludwig8f3a8362020-06-29 17:27:00 -040085protected:
John Stiles933abe32020-08-28 11:58:40 -040086 const Context& fContext;
Brian Osmaneb0f29d2021-08-04 11:34:16 -040087 const Variable& fChild;
Brian Osman4d571112021-04-27 09:10:10 -040088 const bool fWritesToSampleCoords;
Brian Osman1298bc42020-06-30 13:39:35 -040089 SampleUsage fUsage;
Brian Osman8cdf28f2021-05-24 09:52:39 -040090 int fElidedSampleCoordCount = 0;
Michael Ludwig8f3a8362020-06-29 17:27:00 -040091
92 bool visitExpression(const Expression& e) override {
Brian Osmaneb0f29d2021-08-04 11:34:16 -040093 // Looking for child(...)
94 if (e.is<ChildCall>() && &e.as<ChildCall>().child() == &fChild) {
95 // Determine the type of call at this site, and merge it with the accumulated state
96 const ExpressionArray& arguments = e.as<ChildCall>().arguments();
97 SkASSERT(arguments.size() >= 1);
98
99 const Expression* maybeCoords = arguments[0].get();
100 if (maybeCoords->type() == *fContext.fTypes.fFloat2) {
101 // If the coords are a direct reference to the program's sample-coords, and those
102 // coords are never modified, we can conservatively turn this into PassThrough
103 // sampling. In all other cases, we consider it Explicit.
104 if (!fWritesToSampleCoords && maybeCoords->is<VariableReference>() &&
105 maybeCoords->as<VariableReference>().variable()->modifiers().fLayout.fBuiltin ==
106 SK_MAIN_COORDS_BUILTIN) {
Brian Osman1298bc42020-06-30 13:39:35 -0400107 fUsage.merge(SampleUsage::PassThrough());
Brian Osmaneb0f29d2021-08-04 11:34:16 -0400108 ++fElidedSampleCoordCount;
109 } else {
110 fUsage.merge(SampleUsage::Explicit());
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400111 }
Brian Osmaneb0f29d2021-08-04 11:34:16 -0400112 } else {
113 // child(inputColor) or child(srcColor, dstColor) -> PassThrough
114 fUsage.merge(SampleUsage::PassThrough());
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400115 }
116 }
117
John Stilesd7ab4502020-09-24 22:41:00 -0400118 return INHERITED::visitExpression(e);
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400119 }
120
John Stiles7571f9e2020-09-02 22:42:33 -0400121 using INHERITED = ProgramVisitor;
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400122};
123
Brian Osman92aac1e2020-08-05 16:48:58 -0400124// Visitor that searches through the program for references to a particular builtin variable
125class BuiltinVariableVisitor : public ProgramVisitor {
126public:
127 BuiltinVariableVisitor(int builtin) : fBuiltin(builtin) {}
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400128
129 bool visitExpression(const Expression& e) override {
Brian Osman79457ef2020-09-24 15:01:27 -0400130 if (e.is<VariableReference>()) {
John Stiles403a3632020-08-20 12:11:48 -0400131 const VariableReference& var = e.as<VariableReference>();
Ethan Nicholas78686922020-10-08 06:46:27 -0400132 return var.variable()->modifiers().fLayout.fBuiltin == fBuiltin;
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400133 }
John Stilesd7ab4502020-09-24 22:41:00 -0400134 return INHERITED::visitExpression(e);
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400135 }
136
Brian Osman92aac1e2020-08-05 16:48:58 -0400137 int fBuiltin;
138
John Stiles7571f9e2020-09-02 22:42:33 -0400139 using INHERITED = ProgramVisitor;
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400140};
141
Brian Osmaneb0f29d2021-08-04 11:34:16 -0400142// Visitor that searches for child calls from a function other than main()
Brian Osman04d79fc2021-07-02 13:25:35 -0400143class SampleOutsideMainVisitor : public ProgramVisitor {
144public:
145 SampleOutsideMainVisitor() {}
146
147 bool visitExpression(const Expression& e) override {
Brian Osmaneb0f29d2021-08-04 11:34:16 -0400148 if (e.is<ChildCall>()) {
149 return true;
Brian Osman04d79fc2021-07-02 13:25:35 -0400150 }
151 return INHERITED::visitExpression(e);
152 }
153
154 bool visitProgramElement(const ProgramElement& p) override {
155 return p.is<FunctionDefinition>() &&
156 !p.as<FunctionDefinition>().declaration().isMain() &&
157 INHERITED::visitProgramElement(p);
158 }
159
160 using INHERITED = ProgramVisitor;
161};
162
Ethan Nicholas6e0fa402020-08-20 14:08:23 -0400163// Visitor that counts the number of nodes visited
164class NodeCountVisitor : public ProgramVisitor {
165public:
John Stiles2c1e4922020-10-01 09:14:14 -0400166 NodeCountVisitor(int limit) : fLimit(limit) {}
167
Ethan Nicholas6e0fa402020-08-20 14:08:23 -0400168 int visit(const Statement& s) {
Ethan Nicholas6e0fa402020-08-20 14:08:23 -0400169 this->visitStatement(s);
170 return fCount;
171 }
172
173 bool visitExpression(const Expression& e) override {
174 ++fCount;
John Stiles9b9415e2020-11-23 14:48:06 -0500175 return (fCount >= fLimit) || INHERITED::visitExpression(e);
Ethan Nicholas6e0fa402020-08-20 14:08:23 -0400176 }
177
178 bool visitProgramElement(const ProgramElement& p) override {
179 ++fCount;
John Stiles9b9415e2020-11-23 14:48:06 -0500180 return (fCount >= fLimit) || INHERITED::visitProgramElement(p);
Ethan Nicholas6e0fa402020-08-20 14:08:23 -0400181 }
182
183 bool visitStatement(const Statement& s) override {
184 ++fCount;
John Stiles9b9415e2020-11-23 14:48:06 -0500185 return (fCount >= fLimit) || INHERITED::visitStatement(s);
Ethan Nicholas6e0fa402020-08-20 14:08:23 -0400186 }
187
188private:
John Stiles2c1e4922020-10-01 09:14:14 -0400189 int fCount = 0;
190 int fLimit;
Ethan Nicholas6e0fa402020-08-20 14:08:23 -0400191
John Stiles7571f9e2020-09-02 22:42:33 -0400192 using INHERITED = ProgramVisitor;
Ethan Nicholas6e0fa402020-08-20 14:08:23 -0400193};
194
Brian Osman010ce6a2020-10-19 16:34:10 -0400195class ProgramUsageVisitor : public ProgramVisitor {
Brian Osman2e25ff42020-10-15 10:32:04 -0400196public:
Brian Osman010ce6a2020-10-19 16:34:10 -0400197 ProgramUsageVisitor(ProgramUsage* usage, int delta) : fUsage(usage), fDelta(delta) {}
198
John Stiles39465b82021-03-18 09:19:55 -0400199 bool visitProgramElement(const ProgramElement& pe) override {
200 if (pe.is<FunctionDefinition>()) {
201 for (const Variable* param : pe.as<FunctionDefinition>().declaration().parameters()) {
202 // Ensure function-parameter variables exist in the variable usage map. They aren't
203 // otherwise declared, but ProgramUsage::get() should be able to find them, even if
204 // they are unread and unwritten.
205 fUsage->fVariableCounts[param];
206 }
John Stiles8e2a84b2021-04-19 09:35:38 -0400207 } else if (pe.is<InterfaceBlock>()) {
208 // Ensure interface-block variables exist in the variable usage map.
209 fUsage->fVariableCounts[&pe.as<InterfaceBlock>().variable()];
John Stiles39465b82021-03-18 09:19:55 -0400210 }
211 return INHERITED::visitProgramElement(pe);
212 }
213
John Stiles04a8a542021-03-10 19:03:26 -0500214 bool visitStatement(const Statement& s) override {
215 if (s.is<VarDeclaration>()) {
216 // Add all declared variables to the usage map (even if never otherwise accessed).
217 const VarDeclaration& vd = s.as<VarDeclaration>();
218 ProgramUsage::VariableCounts& counts = fUsage->fVariableCounts[&vd.var()];
219 counts.fDeclared += fDelta;
220 SkASSERT(counts.fDeclared >= 0);
221 if (vd.value()) {
222 // The initial-value expression, when present, counts as a write.
223 counts.fWrite += fDelta;
224 }
225 }
226 return INHERITED::visitStatement(s);
227 }
228
Brian Osman2e25ff42020-10-15 10:32:04 -0400229 bool visitExpression(const Expression& e) override {
230 if (e.is<FunctionCall>()) {
231 const FunctionDeclaration* f = &e.as<FunctionCall>().function();
Brian Osman010ce6a2020-10-19 16:34:10 -0400232 fUsage->fCallCounts[f] += fDelta;
233 SkASSERT(fUsage->fCallCounts[f] >= 0);
234 } else if (e.is<VariableReference>()) {
235 const VariableReference& ref = e.as<VariableReference>();
236 ProgramUsage::VariableCounts& counts = fUsage->fVariableCounts[ref.variable()];
237 switch (ref.refKind()) {
238 case VariableRefKind::kRead:
239 counts.fRead += fDelta;
240 break;
241 case VariableRefKind::kWrite:
242 counts.fWrite += fDelta;
243 break;
244 case VariableRefKind::kReadWrite:
245 case VariableRefKind::kPointer:
246 counts.fRead += fDelta;
247 counts.fWrite += fDelta;
248 break;
249 }
250 SkASSERT(counts.fRead >= 0 && counts.fWrite >= 0);
Brian Osman2e25ff42020-10-15 10:32:04 -0400251 }
252 return INHERITED::visitExpression(e);
253 }
254
Brian Osman010ce6a2020-10-19 16:34:10 -0400255 using ProgramVisitor::visitProgramElement;
256 using ProgramVisitor::visitStatement;
257
258 ProgramUsage* fUsage;
259 int fDelta;
Brian Osman2e25ff42020-10-15 10:32:04 -0400260 using INHERITED = ProgramVisitor;
261};
262
Ethan Nicholas765d2fe2020-08-26 08:29:55 -0400263class VariableWriteVisitor : public ProgramVisitor {
264public:
265 VariableWriteVisitor(const Variable* var)
266 : fVar(var) {}
267
268 bool visit(const Statement& s) {
269 return this->visitStatement(s);
270 }
271
272 bool visitExpression(const Expression& e) override {
Brian Osman79457ef2020-09-24 15:01:27 -0400273 if (e.is<VariableReference>()) {
Ethan Nicholas765d2fe2020-08-26 08:29:55 -0400274 const VariableReference& ref = e.as<VariableReference>();
Ethan Nicholas453f67f2020-10-09 10:43:45 -0400275 if (ref.variable() == fVar &&
276 (ref.refKind() == VariableReference::RefKind::kWrite ||
277 ref.refKind() == VariableReference::RefKind::kReadWrite ||
278 ref.refKind() == VariableReference::RefKind::kPointer)) {
Ethan Nicholas765d2fe2020-08-26 08:29:55 -0400279 return true;
280 }
281 }
John Stilesd7ab4502020-09-24 22:41:00 -0400282 return INHERITED::visitExpression(e);
Ethan Nicholas765d2fe2020-08-26 08:29:55 -0400283 }
284
285private:
286 const Variable* fVar;
287
John Stiles7571f9e2020-09-02 22:42:33 -0400288 using INHERITED = ProgramVisitor;
Ethan Nicholas765d2fe2020-08-26 08:29:55 -0400289};
290
John Stilesa976da72020-09-25 23:06:26 -0400291// If a caller doesn't care about errors, we can use this trivial reporter that just counts up.
292class TrivialErrorReporter : public ErrorReporter {
293public:
John Stilesbb8cf582021-08-26 23:34:59 -0400294 ~TrivialErrorReporter() override { this->reportPendingErrors({}); }
Ethan Nicholas32724122021-09-07 13:49:07 -0400295 void handleError(skstd::string_view, PositionInfo) override {}
John Stilesa976da72020-09-25 23:06:26 -0400296};
297
John Stilesdce4d3e2020-09-25 14:35:13 -0400298// This isn't actually using ProgramVisitor, because it only considers a subset of the fields for
299// any given expression kind. For instance, when indexing an array (e.g. `x[1]`), we only want to
300// know if the base (`x`) is assignable; the index expression (`1`) doesn't need to be.
301class IsAssignableVisitor {
302public:
John Stilesb21fac22020-12-04 15:36:49 -0500303 IsAssignableVisitor(ErrorReporter* errors) : fErrors(errors) {}
John Stilesdce4d3e2020-09-25 14:35:13 -0400304
John Stilesb21fac22020-12-04 15:36:49 -0500305 bool visit(Expression& expr, Analysis::AssignmentInfo* info) {
Ethan Nicholas67a0a8a2021-01-13 12:36:02 -0500306 int oldErrorCount = fErrors->errorCount();
John Stilesdce4d3e2020-09-25 14:35:13 -0400307 this->visitExpression(expr);
John Stilesb21fac22020-12-04 15:36:49 -0500308 if (info) {
309 info->fAssignedVar = fAssignedVar;
John Stilesb21fac22020-12-04 15:36:49 -0500310 }
Ethan Nicholas67a0a8a2021-01-13 12:36:02 -0500311 return fErrors->errorCount() == oldErrorCount;
John Stilesdce4d3e2020-09-25 14:35:13 -0400312 }
313
314 void visitExpression(Expression& expr) {
315 switch (expr.kind()) {
316 case Expression::Kind::kVariableReference: {
317 VariableReference& varRef = expr.as<VariableReference>();
Ethan Nicholas78686922020-10-08 06:46:27 -0400318 const Variable* var = varRef.variable();
Brian Osmane49703f2021-04-19 11:15:24 -0400319 if (var->modifiers().fFlags & (Modifiers::kConst_Flag | Modifiers::kUniform_Flag)) {
John Stilesa976da72020-09-25 23:06:26 -0400320 fErrors->error(expr.fOffset,
Ethan Nicholase2c49992020-10-05 11:49:11 -0400321 "cannot modify immutable variable '" + var->name() + "'");
John Stilesb21fac22020-12-04 15:36:49 -0500322 } else {
323 SkASSERT(fAssignedVar == nullptr);
324 fAssignedVar = &varRef;
John Stilesdce4d3e2020-09-25 14:35:13 -0400325 }
326 break;
327 }
328 case Expression::Kind::kFieldAccess:
Ethan Nicholas7a95b202020-10-09 11:55:40 -0400329 this->visitExpression(*expr.as<FieldAccess>().base());
John Stilesdce4d3e2020-09-25 14:35:13 -0400330 break;
331
332 case Expression::Kind::kSwizzle: {
333 const Swizzle& swizzle = expr.as<Swizzle>();
334 this->checkSwizzleWrite(swizzle);
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400335 this->visitExpression(*swizzle.base());
John Stilesdce4d3e2020-09-25 14:35:13 -0400336 break;
337 }
John Stiles47c0a742021-02-09 09:30:35 -0500338 case Expression::Kind::kIndex:
339 this->visitExpression(*expr.as<IndexExpression>().base());
John Stilesdce4d3e2020-09-25 14:35:13 -0400340 break;
John Stiles47c0a742021-02-09 09:30:35 -0500341
Ethan Nicholasc898d042021-08-28 19:53:34 -0400342 case Expression::Kind::kPoison:
343 break;
344
John Stilesdce4d3e2020-09-25 14:35:13 -0400345 default:
John Stilesa976da72020-09-25 23:06:26 -0400346 fErrors->error(expr.fOffset, "cannot assign to this expression");
John Stilesdce4d3e2020-09-25 14:35:13 -0400347 break;
348 }
349 }
350
351private:
352 void checkSwizzleWrite(const Swizzle& swizzle) {
353 int bits = 0;
John Stiles6e88e042021-02-19 14:09:38 -0500354 for (int8_t idx : swizzle.components()) {
355 SkASSERT(idx >= SwizzleComponent::X && idx <= SwizzleComponent::W);
John Stilesdce4d3e2020-09-25 14:35:13 -0400356 int bit = 1 << idx;
357 if (bits & bit) {
John Stilesa976da72020-09-25 23:06:26 -0400358 fErrors->error(swizzle.fOffset,
359 "cannot write to the same swizzle field more than once");
John Stilesdce4d3e2020-09-25 14:35:13 -0400360 break;
361 }
362 bits |= bit;
363 }
364 }
365
John Stilesa976da72020-09-25 23:06:26 -0400366 ErrorReporter* fErrors;
John Stilesb21fac22020-12-04 15:36:49 -0500367 VariableReference* fAssignedVar = nullptr;
John Stilesdce4d3e2020-09-25 14:35:13 -0400368
369 using INHERITED = ProgramVisitor;
370};
371
John Stiles642cde22021-02-23 14:57:01 -0500372class SwitchCaseContainsExit : public ProgramVisitor {
373public:
374 SwitchCaseContainsExit(bool conditionalExits) : fConditionalExits(conditionalExits) {}
375
376 bool visitStatement(const Statement& stmt) override {
377 switch (stmt.kind()) {
378 case Statement::Kind::kBlock:
John Stilesa0e56e32021-03-03 13:14:37 -0500379 case Statement::Kind::kSwitchCase:
John Stiles642cde22021-02-23 14:57:01 -0500380 return INHERITED::visitStatement(stmt);
381
382 case Statement::Kind::kReturn:
383 // Returns are an early exit regardless of the surrounding control structures.
384 return fConditionalExits ? fInConditional : !fInConditional;
385
386 case Statement::Kind::kContinue:
387 // Continues are an early exit from switches, but not loops.
388 return !fInLoop &&
389 (fConditionalExits ? fInConditional : !fInConditional);
390
391 case Statement::Kind::kBreak:
392 // Breaks cannot escape from switches or loops.
393 return !fInLoop && !fInSwitch &&
394 (fConditionalExits ? fInConditional : !fInConditional);
395
396 case Statement::Kind::kIf: {
397 ++fInConditional;
398 bool result = INHERITED::visitStatement(stmt);
399 --fInConditional;
400 return result;
401 }
402
403 case Statement::Kind::kFor:
404 case Statement::Kind::kDo: {
405 // Loops are treated as conditionals because a loop could potentially execute zero
406 // times. We don't have a straightforward way to determine that a loop definitely
407 // executes at least once.
408 ++fInConditional;
409 ++fInLoop;
410 bool result = INHERITED::visitStatement(stmt);
411 --fInLoop;
412 --fInConditional;
413 return result;
414 }
415
416 case Statement::Kind::kSwitch: {
417 ++fInSwitch;
418 bool result = INHERITED::visitStatement(stmt);
419 --fInSwitch;
420 return result;
421 }
422
423 default:
424 return false;
425 }
426 }
427
428 bool fConditionalExits = false;
429 int fInConditional = 0;
430 int fInLoop = 0;
431 int fInSwitch = 0;
432 using INHERITED = ProgramVisitor;
433};
434
John Stilesb3dcbb12021-03-04 16:00:20 -0500435class ReturnsOnAllPathsVisitor : public ProgramVisitor {
436public:
437 bool visitExpression(const Expression& expr) override {
438 // We can avoid processing expressions entirely.
439 return false;
440 }
441
442 bool visitStatement(const Statement& stmt) override {
443 switch (stmt.kind()) {
444 // Returns, breaks, or continues will stop the scan, so only one of these should ever be
445 // true.
446 case Statement::Kind::kReturn:
447 fFoundReturn = true;
448 return true;
449
450 case Statement::Kind::kBreak:
451 fFoundBreak = true;
452 return true;
453
454 case Statement::Kind::kContinue:
455 fFoundContinue = true;
456 return true;
457
458 case Statement::Kind::kIf: {
459 const IfStatement& i = stmt.as<IfStatement>();
460 ReturnsOnAllPathsVisitor trueVisitor;
461 ReturnsOnAllPathsVisitor falseVisitor;
462 trueVisitor.visitStatement(*i.ifTrue());
463 if (i.ifFalse()) {
464 falseVisitor.visitStatement(*i.ifFalse());
465 }
466 // If either branch leads to a break or continue, we report the entire if as
467 // containing a break or continue, since we don't know which side will be reached.
468 fFoundBreak = (trueVisitor.fFoundBreak || falseVisitor.fFoundBreak);
469 fFoundContinue = (trueVisitor.fFoundContinue || falseVisitor.fFoundContinue);
470 // On the other hand, we only want to report returns that definitely happen, so we
471 // require those to be found on both sides.
472 fFoundReturn = (trueVisitor.fFoundReturn && falseVisitor.fFoundReturn);
473 return fFoundBreak || fFoundContinue || fFoundReturn;
474 }
475 case Statement::Kind::kFor: {
476 const ForStatement& f = stmt.as<ForStatement>();
477 // We assume a for/while loop runs for at least one iteration; this isn't strictly
478 // guaranteed, but it's better to be slightly over-permissive here than to fail on
479 // reasonable code.
480 ReturnsOnAllPathsVisitor forVisitor;
481 forVisitor.visitStatement(*f.statement());
482 // A for loop that contains a break or continue is safe; it won't exit the entire
483 // function, just the loop. So we disregard those signals.
484 fFoundReturn = forVisitor.fFoundReturn;
485 return fFoundReturn;
486 }
487 case Statement::Kind::kDo: {
488 const DoStatement& d = stmt.as<DoStatement>();
489 // Do-while blocks are always entered at least once.
490 ReturnsOnAllPathsVisitor doVisitor;
491 doVisitor.visitStatement(*d.statement());
492 // A do-while loop that contains a break or continue is safe; it won't exit the
493 // entire function, just the loop. So we disregard those signals.
494 fFoundReturn = doVisitor.fFoundReturn;
495 return fFoundReturn;
496 }
497 case Statement::Kind::kBlock:
498 // Blocks are definitely entered and don't imply any additional control flow.
499 // If the block contains a break, continue or return, we want to keep that.
500 return INHERITED::visitStatement(stmt);
501
502 case Statement::Kind::kSwitch: {
503 // Switches are the most complex control flow we need to deal with; fortunately we
504 // already have good primitives for dissecting them. We need to verify that:
505 // - a default case exists, so that every possible input value is covered
506 // - every switch-case either (a) returns unconditionally, or
507 // (b) falls through to another case that does
508 const SwitchStatement& s = stmt.as<SwitchStatement>();
509 bool foundDefault = false;
510 bool fellThrough = false;
John Stiles628777c2021-08-04 22:07:41 -0400511 for (const std::unique_ptr<Statement>& switchStmt : s.cases()) {
John Stilesb3dcbb12021-03-04 16:00:20 -0500512 // The default case is indicated by a null value. A switch without a default
513 // case cannot definitively return, as its value might not be in the cases list.
John Stiles628777c2021-08-04 22:07:41 -0400514 const SwitchCase& sc = switchStmt->as<SwitchCase>();
John Stilesb23a64b2021-03-11 08:27:59 -0500515 if (!sc.value()) {
John Stilesb3dcbb12021-03-04 16:00:20 -0500516 foundDefault = true;
517 }
518 // Scan this switch-case for any exit (break, continue or return).
519 ReturnsOnAllPathsVisitor caseVisitor;
John Stilesb23a64b2021-03-11 08:27:59 -0500520 caseVisitor.visitStatement(sc);
John Stilesb3dcbb12021-03-04 16:00:20 -0500521
522 // If we found a break or continue, whether conditional or not, this switch case
523 // can't be called an unconditional return. Switches absorb breaks but not
524 // continues.
525 if (caseVisitor.fFoundContinue) {
526 fFoundContinue = true;
527 return false;
528 }
529 if (caseVisitor.fFoundBreak) {
530 return false;
531 }
532 // We just confirmed that there weren't any breaks or continues. If we didn't
533 // find an unconditional return either, the switch is considered fallen-through.
534 // (There might be a conditional return, but that doesn't count.)
535 fellThrough = !caseVisitor.fFoundReturn;
536 }
537
538 // If we didn't find a default case, or the very last case fell through, this switch
539 // doesn't meet our criteria.
540 if (fellThrough || !foundDefault) {
541 return false;
542 }
543
544 // We scanned the entire switch, found a default case, and every section either fell
545 // through or contained an unconditional return.
546 fFoundReturn = true;
547 return true;
548 }
549
550 case Statement::Kind::kSwitchCase:
551 // Recurse into the switch-case.
552 return INHERITED::visitStatement(stmt);
553
554 case Statement::Kind::kDiscard:
555 case Statement::Kind::kExpression:
556 case Statement::Kind::kInlineMarker:
557 case Statement::Kind::kNop:
558 case Statement::Kind::kVarDeclaration:
559 // None of these statements could contain a return.
560 break;
561 }
562
563 return false;
564 }
565
566 bool fFoundReturn = false;
567 bool fFoundBreak = false;
568 bool fFoundContinue = false;
569
570 using INHERITED = ProgramVisitor;
571};
572
John Stilesa6841be2020-08-06 14:11:56 -0400573} // namespace
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400574
575////////////////////////////////////////////////////////////////////////////////
576// Analysis
577
Brian Osman4d571112021-04-27 09:10:10 -0400578SampleUsage Analysis::GetSampleUsage(const Program& program,
Brian Osman293497e2021-08-24 14:08:50 -0400579 const Variable& child,
Brian Osman8cdf28f2021-05-24 09:52:39 -0400580 bool writesToSampleCoords,
581 int* elidedSampleCoordCount) {
Brian Osman293497e2021-08-24 14:08:50 -0400582 MergeSampleUsageVisitor visitor(*program.fContext, child, writesToSampleCoords);
Brian Osman8cdf28f2021-05-24 09:52:39 -0400583 SampleUsage result = visitor.visit(program);
584 if (elidedSampleCoordCount) {
585 *elidedSampleCoordCount += visitor.elidedSampleCoordCount();
586 }
587 return result;
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400588}
589
Brian Osman92aac1e2020-08-05 16:48:58 -0400590bool Analysis::ReferencesBuiltin(const Program& program, int builtin) {
591 BuiltinVariableVisitor visitor(builtin);
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400592 return visitor.visit(program);
593}
594
Brian Osman92aac1e2020-08-05 16:48:58 -0400595bool Analysis::ReferencesSampleCoords(const Program& program) {
596 return Analysis::ReferencesBuiltin(program, SK_MAIN_COORDS_BUILTIN);
597}
598
599bool Analysis::ReferencesFragCoords(const Program& program) {
600 return Analysis::ReferencesBuiltin(program, SK_FRAGCOORD_BUILTIN);
601}
602
Brian Osman04d79fc2021-07-02 13:25:35 -0400603bool Analysis::CallsSampleOutsideMain(const Program& program) {
604 SampleOutsideMainVisitor visitor;
605 return visitor.visit(program);
606}
607
John Stiles61e5e202021-09-02 09:56:31 -0400608bool Analysis::CheckProgramUnrolledSize(const Program& program) {
609 // We check the size of strict-ES2 programs since SkVM will completely unroll them.
610 // Note that we *cannot* safely check the program size of non-ES2 code at this time, as it is
611 // allowed to do things we can't measure (e.g. the program can contain a recursive cycle). We
612 // could, at best, compute a lower bound.
613 const Context& context = *program.fContext;
614 SkASSERT(context.fConfig->strictES2Mode());
615
616 // If we decide that expressions are cheaper than statements, or that certain statements are
617 // more expensive than others, etc., we can always tweak these ratios as needed. A very rough
618 // ballpark estimate is currently good enough for our purposes.
John Stilesa047e8b2021-09-15 11:41:02 -0400619 static constexpr size_t kExpressionCost = 1;
620 static constexpr size_t kStatementCost = 1;
621 static constexpr size_t kUnknownCost = -1;
622 static constexpr size_t kProgramSizeLimit = 100000;
623 static constexpr size_t kProgramStackDepthLimit = 50;
John Stiles61e5e202021-09-02 09:56:31 -0400624
625 class ProgramSizeVisitor : public ProgramVisitor {
626 public:
John Stiles6475b102021-09-02 14:09:23 -0400627 ProgramSizeVisitor(const Context& c) : fContext(c) {}
John Stiles61e5e202021-09-02 09:56:31 -0400628
629 using ProgramVisitor::visitProgramElement;
630
John Stilesa047e8b2021-09-15 11:41:02 -0400631 size_t functionSize() const {
John Stiles6475b102021-09-02 14:09:23 -0400632 return fFunctionSize;
633 }
634
635 bool visitProgramElement(const ProgramElement& pe) override {
636 if (pe.is<FunctionDefinition>()) {
637 // Check the function-size cache map first. We don't need to visit this function if
638 // we already processed it before.
639 const FunctionDeclaration* decl = &pe.as<FunctionDefinition>().declaration();
640 auto [iter, wasInserted] = fFunctionCostMap.insert({decl, kUnknownCost});
641 if (!wasInserted) {
642 // We already have this function in our map. We don't need to check it again.
643 if (iter->second == kUnknownCost) {
644 // If the function is present in the map with an unknown cost, we're
645 // recursively processing it--in other words, we found a cycle in the code.
John Stiles98ddea02021-09-02 14:33:08 -0400646 // Unwind our stack into a string.
647 String msg = "\n\t" + decl->description();
648 for (auto unwind = fStack.rbegin(); unwind != fStack.rend(); ++unwind) {
649 msg = "\n\t" + (*unwind)->description() + msg;
650 if (*unwind == decl) {
651 break;
652 }
653 }
654 msg = "potential recursion (function call cycle) not allowed:" + msg;
655 fContext.fErrors->error(pe.fOffset, std::move(msg));
John Stiles6475b102021-09-02 14:09:23 -0400656 fFunctionSize = iter->second = 0;
657 return true;
658 }
659 // Set the size to its known value.
660 fFunctionSize = iter->second;
661 return false;
662 }
663
John Stiles2af4b132021-09-02 16:17:07 -0400664 // If the function-call stack has gotten too deep, stop the analysis.
665 if (fStack.size() >= kProgramStackDepthLimit) {
666 String msg = "exceeded max function call depth:";
667 for (auto unwind = fStack.begin(); unwind != fStack.end(); ++unwind) {
668 msg += "\n\t" + (*unwind)->description();
669 }
670 msg += "\n\t" + decl->description();
671 fContext.fErrors->error(pe.fOffset, std::move(msg));
672 fFunctionSize = iter->second = 0;
673 return true;
674 }
675
John Stiles6475b102021-09-02 14:09:23 -0400676 // Calculate the function cost and store it in our cache.
John Stiles98ddea02021-09-02 14:33:08 -0400677 fStack.push_back(decl);
John Stiles6475b102021-09-02 14:09:23 -0400678 fFunctionSize = 0;
John Stiles6475b102021-09-02 14:09:23 -0400679 bool result = INHERITED::visitProgramElement(pe);
680 iter->second = fFunctionSize;
John Stiles98ddea02021-09-02 14:33:08 -0400681 fStack.pop_back();
682
John Stiles6475b102021-09-02 14:09:23 -0400683 return result;
684 }
685
686 return INHERITED::visitProgramElement(pe);
John Stiles61e5e202021-09-02 09:56:31 -0400687 }
688
689 bool visitStatement(const Statement& stmt) override {
690 switch (stmt.kind()) {
691 case Statement::Kind::kFor: {
692 // We count a for-loop's unrolled size here. We expect that the init statement
693 // will be emitted once, and the next-expr and statement will be repeated in the
694 // output for every iteration of the loop. The test-expr is optimized away
695 // during the unroll and is not counted at all.
696 const ForStatement& forStmt = stmt.as<ForStatement>();
John Stilesa047e8b2021-09-15 11:41:02 -0400697 bool result = this->visitStatement(*forStmt.initializer());
John Stiles61e5e202021-09-02 09:56:31 -0400698
John Stilesa047e8b2021-09-15 11:41:02 -0400699 size_t originalFunctionSize = fFunctionSize;
700 fFunctionSize = 0;
John Stiles61e5e202021-09-02 09:56:31 -0400701
John Stiles78b84cc2021-09-15 09:44:54 -0400702 result = this->visitExpression(*forStmt.next()) ||
703 this->visitStatement(*forStmt.statement()) || result;
John Stiles61e5e202021-09-02 09:56:31 -0400704
John Stilesa047e8b2021-09-15 11:41:02 -0400705 if (const LoopUnrollInfo* unrollInfo = forStmt.unrollInfo()) {
706 fFunctionSize = SkSafeMath::Mul(fFunctionSize, unrollInfo->fCount);
707 } else {
708 SkDEBUGFAIL("for-loops should always have unroll info in an ES2 program");
709 }
710
711 fFunctionSize = SkSafeMath::Add(fFunctionSize, originalFunctionSize);
John Stiles61e5e202021-09-02 09:56:31 -0400712 return result;
713 }
714
715 case Statement::Kind::kExpression:
716 // The cost of an expression-statement is counted in visitExpression. It would
717 // be double-dipping to count it here too.
718 break;
719
720 case Statement::Kind::kInlineMarker:
721 case Statement::Kind::kNop:
722 case Statement::Kind::kVarDeclaration:
723 // These statements don't directly consume any space in a compiled program.
724 break;
725
726 case Statement::Kind::kDo:
John Stiles61e5e202021-09-02 09:56:31 -0400727 SkDEBUGFAIL("encountered a statement that shouldn't exist in an ES2 program");
728 break;
729
730 default:
John Stilesa047e8b2021-09-15 11:41:02 -0400731 fFunctionSize = SkSafeMath::Add(fFunctionSize, kStatementCost);
John Stiles61e5e202021-09-02 09:56:31 -0400732 break;
733 }
734
John Stilesa047e8b2021-09-15 11:41:02 -0400735 bool earlyExit = fFunctionSize > kProgramSizeLimit;
736 return earlyExit || INHERITED::visitStatement(stmt);
John Stiles61e5e202021-09-02 09:56:31 -0400737 }
738
739 bool visitExpression(const Expression& expr) override {
740 // Other than function calls, all expressions are assumed to have a fixed unit cost.
John Stiles6475b102021-09-02 14:09:23 -0400741 bool earlyExit = false;
John Stilesa047e8b2021-09-15 11:41:02 -0400742 size_t expressionCost = kExpressionCost;
John Stiles61e5e202021-09-02 09:56:31 -0400743
744 if (expr.is<FunctionCall>()) {
John Stiles6475b102021-09-02 14:09:23 -0400745 // Visit this function call to calculate its size. If we've already sized it, this
746 // will retrieve the size from our cache.
John Stiles61e5e202021-09-02 09:56:31 -0400747 const FunctionCall& call = expr.as<FunctionCall>();
748 const FunctionDeclaration* decl = &call.function();
John Stiles61e5e202021-09-02 09:56:31 -0400749 if (decl->definition() && !decl->isIntrinsic()) {
John Stilesa047e8b2021-09-15 11:41:02 -0400750 size_t originalFunctionSize = fFunctionSize;
751 fFunctionSize = 0;
John Stiles61e5e202021-09-02 09:56:31 -0400752
John Stiles6475b102021-09-02 14:09:23 -0400753 earlyExit = this->visitProgramElement(*decl->definition());
754 expressionCost = fFunctionSize;
John Stiles61e5e202021-09-02 09:56:31 -0400755
John Stiles6475b102021-09-02 14:09:23 -0400756 fFunctionSize = originalFunctionSize;
John Stiles61e5e202021-09-02 09:56:31 -0400757 }
758 }
759
John Stilesa047e8b2021-09-15 11:41:02 -0400760 fFunctionSize = SkSafeMath::Add(fFunctionSize, expressionCost);
John Stiles6475b102021-09-02 14:09:23 -0400761 return earlyExit || INHERITED::visitExpression(expr);
John Stiles61e5e202021-09-02 09:56:31 -0400762 }
763
764 private:
765 using INHERITED = ProgramVisitor;
766
John Stiles36ddccc2021-09-03 10:57:04 -0400767 const Context& fContext;
John Stilesa047e8b2021-09-15 11:41:02 -0400768 size_t fFunctionSize = 0;
769 std::unordered_map<const FunctionDeclaration*, size_t> fFunctionCostMap;
John Stiles98ddea02021-09-02 14:33:08 -0400770 std::vector<const FunctionDeclaration*> fStack;
John Stiles61e5e202021-09-02 09:56:31 -0400771 };
772
John Stiles6475b102021-09-02 14:09:23 -0400773 // Process every function in our program.
774 ProgramSizeVisitor visitor{context};
John Stiles61e5e202021-09-02 09:56:31 -0400775 for (const std::unique_ptr<ProgramElement>& element : program.ownedElements()) {
John Stiles6475b102021-09-02 14:09:23 -0400776 if (element->is<FunctionDefinition>()) {
777 // Visit every function--we want to detect static recursion and report it as an error,
778 // even in unreferenced functions.
John Stiles61e5e202021-09-02 09:56:31 -0400779 visitor.visitProgramElement(*element);
John Stiles6475b102021-09-02 14:09:23 -0400780 // Report an error when main()'s flattened size is larger than our program limit.
781 if (visitor.functionSize() > kProgramSizeLimit &&
782 element->as<FunctionDefinition>().declaration().isMain()) {
783 context.fErrors->error(/*offset=*/-1, "program is too large");
784 }
John Stiles61e5e202021-09-02 09:56:31 -0400785 }
786 }
787
John Stiles61e5e202021-09-02 09:56:31 -0400788 return true;
789}
790
Ethan Nicholas98eae1e2021-09-01 14:37:29 -0400791bool Analysis::DetectVarDeclarationWithoutScope(const Statement& stmt, ErrorReporter* errors) {
792 // A variable declaration can create either a lone VarDeclaration or an unscoped Block
793 // containing multiple VarDeclaration statements. We need to detect either case.
794 const Variable* var;
795 if (stmt.is<VarDeclaration>()) {
796 // The single-variable case. No blocks at all.
797 var = &stmt.as<VarDeclaration>().var();
798 } else if (stmt.is<Block>()) {
799 // The multiple-variable case: an unscoped, non-empty block...
800 const Block& block = stmt.as<Block>();
801 if (block.isScope() || block.children().empty()) {
802 return false;
803 }
804 // ... holding a variable declaration.
805 const Statement& innerStmt = *block.children().front();
806 if (!innerStmt.is<VarDeclaration>()) {
807 return false;
808 }
809 var = &innerStmt.as<VarDeclaration>().var();
810 } else {
811 // This statement wasn't a variable declaration. No problem.
812 return false;
813 }
814
815 // Report an error.
816 SkASSERT(var);
817 if (errors) {
818 errors->error(stmt.fOffset, "variable '" + var->name() + "' must be created in a scope");
819 }
820 return true;
821}
822
John Stiles9b9415e2020-11-23 14:48:06 -0500823int Analysis::NodeCountUpToLimit(const FunctionDefinition& function, int limit) {
824 return NodeCountVisitor{limit}.visit(*function.body());
Ethan Nicholas6e0fa402020-08-20 14:08:23 -0400825}
826
John Stiles642cde22021-02-23 14:57:01 -0500827bool Analysis::SwitchCaseContainsUnconditionalExit(Statement& stmt) {
828 return SwitchCaseContainsExit{/*conditionalExits=*/false}.visitStatement(stmt);
829}
830
831bool Analysis::SwitchCaseContainsConditionalExit(Statement& stmt) {
832 return SwitchCaseContainsExit{/*conditionalExits=*/true}.visitStatement(stmt);
833}
834
Brian Osman010ce6a2020-10-19 16:34:10 -0400835std::unique_ptr<ProgramUsage> Analysis::GetUsage(const Program& program) {
836 auto usage = std::make_unique<ProgramUsage>();
837 ProgramUsageVisitor addRefs(usage.get(), /*delta=*/+1);
838 addRefs.visit(program);
839 return usage;
840}
841
Brian Osman0006ad02020-11-18 15:38:39 -0500842std::unique_ptr<ProgramUsage> Analysis::GetUsage(const LoadedModule& module) {
843 auto usage = std::make_unique<ProgramUsage>();
844 ProgramUsageVisitor addRefs(usage.get(), /*delta=*/+1);
845 for (const auto& element : module.fElements) {
846 addRefs.visitProgramElement(*element);
847 }
848 return usage;
849}
850
Brian Osman010ce6a2020-10-19 16:34:10 -0400851ProgramUsage::VariableCounts ProgramUsage::get(const Variable& v) const {
John Stiles04a8a542021-03-10 19:03:26 -0500852 const VariableCounts* counts = fVariableCounts.find(&v);
853 SkASSERT(counts);
854 return *counts;
Brian Osman010ce6a2020-10-19 16:34:10 -0400855}
856
857bool ProgramUsage::isDead(const Variable& v) const {
858 const Modifiers& modifiers = v.modifiers();
859 VariableCounts counts = this->get(v);
860 if ((v.storage() != Variable::Storage::kLocal && counts.fRead) ||
Brian Osmane49703f2021-04-19 11:15:24 -0400861 (modifiers.fFlags &
862 (Modifiers::kIn_Flag | Modifiers::kOut_Flag | Modifiers::kUniform_Flag))) {
Brian Osman010ce6a2020-10-19 16:34:10 -0400863 return false;
864 }
John Stilesf10eff32021-03-16 10:57:55 -0400865 // Consider the variable dead if it's never read and never written (besides the initial-value).
866 return !counts.fRead && (counts.fWrite <= (v.initialValue() ? 1 : 0));
Brian Osman010ce6a2020-10-19 16:34:10 -0400867}
868
869int ProgramUsage::get(const FunctionDeclaration& f) const {
870 const int* count = fCallCounts.find(&f);
871 return count ? *count : 0;
872}
873
John Stiles60dbf072021-08-02 14:22:34 -0400874void ProgramUsage::add(const Expression* expr) {
875 ProgramUsageVisitor addRefs(this, /*delta=*/+1);
876 addRefs.visitExpression(*expr);
Brian Osman010ce6a2020-10-19 16:34:10 -0400877}
878
879void ProgramUsage::add(const Statement* stmt) {
880 ProgramUsageVisitor addRefs(this, /*delta=*/+1);
881 addRefs.visitStatement(*stmt);
882}
883
John Stiles60dbf072021-08-02 14:22:34 -0400884void ProgramUsage::add(const ProgramElement& element) {
885 ProgramUsageVisitor addRefs(this, /*delta=*/+1);
886 addRefs.visitProgramElement(element);
887}
888
Brian Osman010ce6a2020-10-19 16:34:10 -0400889void ProgramUsage::remove(const Expression* expr) {
890 ProgramUsageVisitor subRefs(this, /*delta=*/-1);
891 subRefs.visitExpression(*expr);
892}
893
894void ProgramUsage::remove(const Statement* stmt) {
895 ProgramUsageVisitor subRefs(this, /*delta=*/-1);
896 subRefs.visitStatement(*stmt);
897}
898
899void ProgramUsage::remove(const ProgramElement& element) {
900 ProgramUsageVisitor subRefs(this, /*delta=*/-1);
901 subRefs.visitProgramElement(element);
Brian Osman2e25ff42020-10-15 10:32:04 -0400902}
903
Ethan Nicholas765d2fe2020-08-26 08:29:55 -0400904bool Analysis::StatementWritesToVariable(const Statement& stmt, const Variable& var) {
905 return VariableWriteVisitor(&var).visit(stmt);
906}
907
John Stilesb21fac22020-12-04 15:36:49 -0500908bool Analysis::IsAssignable(Expression& expr, AssignmentInfo* info, ErrorReporter* errors) {
John Stilesa976da72020-09-25 23:06:26 -0400909 TrivialErrorReporter trivialErrors;
John Stilesb21fac22020-12-04 15:36:49 -0500910 return IsAssignableVisitor{errors ? errors : &trivialErrors}.visit(expr, info);
John Stilesdce4d3e2020-09-25 14:35:13 -0400911}
912
John Stilesbb8cf582021-08-26 23:34:59 -0400913bool Analysis::UpdateVariableRefKind(Expression* expr,
914 VariableReference::RefKind kind,
915 ErrorReporter* errors) {
John Stiles516704b2021-02-26 15:01:57 -0500916 Analysis::AssignmentInfo info;
917 if (!Analysis::IsAssignable(*expr, &info, errors)) {
918 return false;
919 }
920 if (!info.fAssignedVar) {
John Stilesbb8cf582021-08-26 23:34:59 -0400921 if (errors) {
922 errors->error(expr->fOffset, "can't assign to expression '" +
923 expr->description() + "'");
924 }
John Stiles516704b2021-02-26 15:01:57 -0500925 return false;
926 }
927 info.fAssignedVar->setRefKind(kind);
928 return true;
929}
930
John Stilesc30fbca2020-11-19 16:25:49 -0500931bool Analysis::IsTrivialExpression(const Expression& expr) {
John Stiles7591d4b2021-09-13 13:32:06 -0400932 return expr.is<Literal>() ||
John Stilesc30fbca2020-11-19 16:25:49 -0500933 expr.is<VariableReference>() ||
934 (expr.is<Swizzle>() &&
935 IsTrivialExpression(*expr.as<Swizzle>().base())) ||
936 (expr.is<FieldAccess>() &&
937 IsTrivialExpression(*expr.as<FieldAccess>().base())) ||
John Stiles2938eea2021-04-01 18:58:25 -0400938 (expr.isAnyConstructor() &&
939 expr.asAnyConstructor().argumentSpan().size() == 1 &&
940 IsTrivialExpression(*expr.asAnyConstructor().argumentSpan().front())) ||
941 (expr.isAnyConstructor() &&
John Stilesc30fbca2020-11-19 16:25:49 -0500942 expr.isConstantOrUniform()) ||
943 (expr.is<IndexExpression>() &&
John Stiles7591d4b2021-09-13 13:32:06 -0400944 expr.as<IndexExpression>().index()->isIntLiteral() &&
John Stilesc30fbca2020-11-19 16:25:49 -0500945 IsTrivialExpression(*expr.as<IndexExpression>().base()));
946}
947
John Stiles5676c572021-03-08 17:10:52 -0500948bool Analysis::IsSameExpressionTree(const Expression& left, const Expression& right) {
John Stiles95d0bad2021-03-01 17:02:28 -0500949 if (left.kind() != right.kind() || left.type() != right.type()) {
950 return false;
951 }
952
John Stiles5676c572021-03-08 17:10:52 -0500953 // This isn't a fully exhaustive list of expressions by any stretch of the imagination; for
954 // instance, `x[y+1] = x[y+1]` isn't detected because we don't look at BinaryExpressions.
955 // Since this is intended to be used for optimization purposes, handling the common cases is
956 // sufficient.
John Stiles95d0bad2021-03-01 17:02:28 -0500957 switch (left.kind()) {
John Stiles7591d4b2021-09-13 13:32:06 -0400958 case Expression::Kind::kLiteral:
959 return left.as<Literal>().value() == right.as<Literal>().value();
John Stiles5676c572021-03-08 17:10:52 -0500960
John Stiles7384b372021-04-01 13:48:15 -0400961 case Expression::Kind::kConstructorArray:
John Stilese3ae9682021-08-05 10:35:01 -0400962 case Expression::Kind::kConstructorArrayCast:
John Stiles8cad6372021-04-07 12:31:13 -0400963 case Expression::Kind::kConstructorCompound:
964 case Expression::Kind::kConstructorCompoundCast:
John Stiles2938eea2021-04-01 18:58:25 -0400965 case Expression::Kind::kConstructorDiagonalMatrix:
John Stiles5abb9e12021-04-06 13:47:19 -0400966 case Expression::Kind::kConstructorMatrixResize:
John Stilesfd7252f2021-04-04 22:24:40 -0400967 case Expression::Kind::kConstructorScalarCast:
John Stilesd47330f2021-04-08 23:25:52 -0400968 case Expression::Kind::kConstructorStruct:
John Stiles268a73f2021-04-07 12:30:22 -0400969 case Expression::Kind::kConstructorSplat: {
John Stilesfd7252f2021-04-04 22:24:40 -0400970 if (left.kind() != right.kind()) {
971 return false;
972 }
John Stiles7384b372021-04-01 13:48:15 -0400973 const AnyConstructor& leftCtor = left.asAnyConstructor();
974 const AnyConstructor& rightCtor = right.asAnyConstructor();
975 const auto leftSpan = leftCtor.argumentSpan();
976 const auto rightSpan = rightCtor.argumentSpan();
977 if (leftSpan.size() != rightSpan.size()) {
John Stiles5676c572021-03-08 17:10:52 -0500978 return false;
979 }
John Stiles7384b372021-04-01 13:48:15 -0400980 for (size_t index = 0; index < leftSpan.size(); ++index) {
981 if (!IsSameExpressionTree(*leftSpan[index], *rightSpan[index])) {
John Stiles5676c572021-03-08 17:10:52 -0500982 return false;
983 }
984 }
985 return true;
986 }
John Stiles95d0bad2021-03-01 17:02:28 -0500987 case Expression::Kind::kFieldAccess:
988 return left.as<FieldAccess>().fieldIndex() == right.as<FieldAccess>().fieldIndex() &&
John Stiles5676c572021-03-08 17:10:52 -0500989 IsSameExpressionTree(*left.as<FieldAccess>().base(),
990 *right.as<FieldAccess>().base());
John Stiles95d0bad2021-03-01 17:02:28 -0500991
992 case Expression::Kind::kIndex:
John Stiles5676c572021-03-08 17:10:52 -0500993 return IsSameExpressionTree(*left.as<IndexExpression>().index(),
994 *right.as<IndexExpression>().index()) &&
995 IsSameExpressionTree(*left.as<IndexExpression>().base(),
996 *right.as<IndexExpression>().base());
John Stiles95d0bad2021-03-01 17:02:28 -0500997
998 case Expression::Kind::kSwizzle:
999 return left.as<Swizzle>().components() == right.as<Swizzle>().components() &&
John Stiles5676c572021-03-08 17:10:52 -05001000 IsSameExpressionTree(*left.as<Swizzle>().base(), *right.as<Swizzle>().base());
John Stiles95d0bad2021-03-01 17:02:28 -05001001
1002 case Expression::Kind::kVariableReference:
1003 return left.as<VariableReference>().variable() ==
1004 right.as<VariableReference>().variable();
1005
1006 default:
1007 return false;
1008 }
1009}
1010
John Stiles232b4ce2021-03-01 22:14:22 -05001011static const char* invalid_for_ES2(int offset,
1012 const Statement* loopInitializer,
1013 const Expression* loopTest,
1014 const Expression* loopNext,
1015 const Statement* loopStatement,
John Stiles9c975c52021-08-31 10:18:57 -04001016 LoopUnrollInfo& loopInfo) {
Brian Osman77ba8102021-01-12 17:15:30 -05001017 //
1018 // init_declaration has the form: type_specifier identifier = constant_expression
1019 //
John Stiles232b4ce2021-03-01 22:14:22 -05001020 if (!loopInitializer) {
Brian Osman77ba8102021-01-12 17:15:30 -05001021 return "missing init declaration";
1022 }
John Stiles232b4ce2021-03-01 22:14:22 -05001023 if (!loopInitializer->is<VarDeclaration>()) {
Brian Osman77ba8102021-01-12 17:15:30 -05001024 return "invalid init declaration";
1025 }
John Stiles232b4ce2021-03-01 22:14:22 -05001026 const VarDeclaration& initDecl = loopInitializer->as<VarDeclaration>();
Brian Osman6c7910e2021-01-14 09:50:52 -05001027 if (!initDecl.baseType().isNumber()) {
Brian Osman77ba8102021-01-12 17:15:30 -05001028 return "invalid type for loop index";
1029 }
1030 if (initDecl.arraySize() != 0) {
1031 return "invalid type for loop index";
1032 }
1033 if (!initDecl.value()) {
1034 return "missing loop index initializer";
1035 }
Brian Osman448b2d52021-09-23 11:36:15 -04001036 if (!ConstantFolder::GetConstantValue(*initDecl.value(), &loopInfo.fStart)) {
Brian Osman77ba8102021-01-12 17:15:30 -05001037 return "loop index initializer must be a constant expression";
1038 }
1039
1040 loopInfo.fIndex = &initDecl.var();
1041
1042 auto is_loop_index = [&](const std::unique_ptr<Expression>& expr) {
1043 return expr->is<VariableReference>() &&
1044 expr->as<VariableReference>().variable() == loopInfo.fIndex;
1045 };
1046
1047 //
1048 // condition has the form: loop_index relational_operator constant_expression
1049 //
John Stiles232b4ce2021-03-01 22:14:22 -05001050 if (!loopTest) {
Brian Osman77ba8102021-01-12 17:15:30 -05001051 return "missing condition";
1052 }
John Stiles232b4ce2021-03-01 22:14:22 -05001053 if (!loopTest->is<BinaryExpression>()) {
Brian Osman77ba8102021-01-12 17:15:30 -05001054 return "invalid condition";
1055 }
John Stiles232b4ce2021-03-01 22:14:22 -05001056 const BinaryExpression& cond = loopTest->as<BinaryExpression>();
Brian Osman77ba8102021-01-12 17:15:30 -05001057 if (!is_loop_index(cond.left())) {
1058 return "expected loop index on left hand side of condition";
1059 }
1060 // relational_operator is one of: > >= < <= == or !=
John Stiles45990502021-02-16 10:55:27 -05001061 switch (cond.getOperator().kind()) {
Brian Osman77ba8102021-01-12 17:15:30 -05001062 case Token::Kind::TK_GT:
1063 case Token::Kind::TK_GTEQ:
1064 case Token::Kind::TK_LT:
1065 case Token::Kind::TK_LTEQ:
1066 case Token::Kind::TK_EQEQ:
1067 case Token::Kind::TK_NEQ:
1068 break;
1069 default:
1070 return "invalid relational operator";
1071 }
1072 double loopEnd = 0;
Brian Osman448b2d52021-09-23 11:36:15 -04001073 if (!ConstantFolder::GetConstantValue(*cond.right(), &loopEnd)) {
Brian Osman77ba8102021-01-12 17:15:30 -05001074 return "loop index must be compared with a constant expression";
1075 }
1076
1077 //
1078 // expression has one of the following forms:
1079 // loop_index++
1080 // loop_index--
1081 // loop_index += constant_expression
1082 // loop_index -= constant_expression
1083 // The spec doesn't mention prefix increment and decrement, but there is some consensus that
1084 // it's an oversight, so we allow those as well.
1085 //
John Stiles232b4ce2021-03-01 22:14:22 -05001086 if (!loopNext) {
Brian Osman77ba8102021-01-12 17:15:30 -05001087 return "missing loop expression";
1088 }
John Stiles232b4ce2021-03-01 22:14:22 -05001089 switch (loopNext->kind()) {
Brian Osman77ba8102021-01-12 17:15:30 -05001090 case Expression::Kind::kBinary: {
John Stiles232b4ce2021-03-01 22:14:22 -05001091 const BinaryExpression& next = loopNext->as<BinaryExpression>();
Brian Osman77ba8102021-01-12 17:15:30 -05001092 if (!is_loop_index(next.left())) {
1093 return "expected loop index in loop expression";
1094 }
Brian Osman448b2d52021-09-23 11:36:15 -04001095 if (!ConstantFolder::GetConstantValue(*next.right(), &loopInfo.fDelta)) {
Brian Osman77ba8102021-01-12 17:15:30 -05001096 return "loop index must be modified by a constant expression";
1097 }
John Stiles45990502021-02-16 10:55:27 -05001098 switch (next.getOperator().kind()) {
Brian Osman77ba8102021-01-12 17:15:30 -05001099 case Token::Kind::TK_PLUSEQ: break;
1100 case Token::Kind::TK_MINUSEQ: loopInfo.fDelta = -loopInfo.fDelta; break;
1101 default:
1102 return "invalid operator in loop expression";
1103 }
1104 } break;
1105 case Expression::Kind::kPrefix: {
John Stiles232b4ce2021-03-01 22:14:22 -05001106 const PrefixExpression& next = loopNext->as<PrefixExpression>();
Brian Osman77ba8102021-01-12 17:15:30 -05001107 if (!is_loop_index(next.operand())) {
1108 return "expected loop index in loop expression";
1109 }
John Stiles45990502021-02-16 10:55:27 -05001110 switch (next.getOperator().kind()) {
Brian Osman77ba8102021-01-12 17:15:30 -05001111 case Token::Kind::TK_PLUSPLUS: loopInfo.fDelta = 1; break;
1112 case Token::Kind::TK_MINUSMINUS: loopInfo.fDelta = -1; break;
1113 default:
1114 return "invalid operator in loop expression";
1115 }
1116 } break;
1117 case Expression::Kind::kPostfix: {
John Stiles232b4ce2021-03-01 22:14:22 -05001118 const PostfixExpression& next = loopNext->as<PostfixExpression>();
Brian Osman77ba8102021-01-12 17:15:30 -05001119 if (!is_loop_index(next.operand())) {
1120 return "expected loop index in loop expression";
1121 }
John Stiles45990502021-02-16 10:55:27 -05001122 switch (next.getOperator().kind()) {
Brian Osman77ba8102021-01-12 17:15:30 -05001123 case Token::Kind::TK_PLUSPLUS: loopInfo.fDelta = 1; break;
1124 case Token::Kind::TK_MINUSMINUS: loopInfo.fDelta = -1; break;
1125 default:
1126 return "invalid operator in loop expression";
1127 }
1128 } break;
1129 default:
1130 return "invalid loop expression";
1131 }
1132
1133 //
1134 // Within the body of the loop, the loop index is not statically assigned to, nor is it used as
1135 // argument to a function 'out' or 'inout' parameter.
1136 //
John Stiles232b4ce2021-03-01 22:14:22 -05001137 if (Analysis::StatementWritesToVariable(*loopStatement, initDecl.var())) {
Brian Osman77ba8102021-01-12 17:15:30 -05001138 return "loop index must not be modified within body of the loop";
1139 }
1140
1141 // Finally, compute the iteration count, based on the bounds, and the termination operator.
John Stiles106e0cd2021-09-07 11:43:51 -04001142 static constexpr int kLoopTerminationLimit = 100000;
Brian Osman77ba8102021-01-12 17:15:30 -05001143 loopInfo.fCount = 0;
1144
John Stiles106e0cd2021-09-07 11:43:51 -04001145 auto calculateCount = [](double start, double end, double delta,
1146 bool forwards, bool inclusive) -> int {
1147 if (forwards != (start < end)) {
1148 // The loop starts in a completed state (the start has already advanced past the end).
1149 return 0;
Brian Osman77ba8102021-01-12 17:15:30 -05001150 }
John Stiles106e0cd2021-09-07 11:43:51 -04001151 if ((delta == 0.0) || forwards != (delta > 0.0)) {
1152 // The loop does not progress toward a completed state, and will never terminate.
1153 return kLoopTerminationLimit;
1154 }
1155 double iterations = sk_ieee_double_divide(end - start, delta);
1156 double count = std::ceil(iterations);
1157 if (inclusive && (count == iterations)) {
1158 count += 1.0;
1159 }
1160 if (count > kLoopTerminationLimit || !std::isfinite(count)) {
1161 // The loop runs for more iterations than we can safely unroll.
1162 return kLoopTerminationLimit;
1163 }
1164 return (int)count;
Brian Osman77ba8102021-01-12 17:15:30 -05001165 };
1166
John Stiles106e0cd2021-09-07 11:43:51 -04001167 switch (cond.getOperator().kind()) {
1168 case Token::Kind::TK_LT:
1169 loopInfo.fCount = calculateCount(loopInfo.fStart, loopEnd, loopInfo.fDelta,
1170 /*forwards=*/true, /*inclusive=*/false);
1171 break;
1172
1173 case Token::Kind::TK_GT:
1174 loopInfo.fCount = calculateCount(loopInfo.fStart, loopEnd, loopInfo.fDelta,
1175 /*forwards=*/false, /*inclusive=*/false);
1176 break;
1177
1178 case Token::Kind::TK_LTEQ:
1179 loopInfo.fCount = calculateCount(loopInfo.fStart, loopEnd, loopInfo.fDelta,
1180 /*forwards=*/true, /*inclusive=*/true);
1181 break;
1182
1183 case Token::Kind::TK_GTEQ:
1184 loopInfo.fCount = calculateCount(loopInfo.fStart, loopEnd, loopInfo.fDelta,
1185 /*forwards=*/false, /*inclusive=*/true);
1186 break;
1187
1188 case Token::Kind::TK_NEQ: {
1189 float iterations = sk_ieee_double_divide(loopEnd - loopInfo.fStart, loopInfo.fDelta);
1190 loopInfo.fCount = std::ceil(iterations);
1191 if (loopInfo.fCount < 0 || loopInfo.fCount != iterations ||
1192 !std::isfinite(iterations)) {
1193 // The loop doesn't reach the exact endpoint and so will never terminate.
1194 loopInfo.fCount = kLoopTerminationLimit;
1195 }
Brian Osman77ba8102021-01-12 17:15:30 -05001196 break;
1197 }
John Stiles106e0cd2021-09-07 11:43:51 -04001198 case Token::Kind::TK_EQEQ: {
1199 if (loopInfo.fStart == loopEnd) {
1200 // Start and end begin in the same place, so we can run one iteration...
1201 if (loopInfo.fDelta) {
1202 // ... and then they diverge, so the loop terminates.
1203 loopInfo.fCount = 1;
1204 } else {
1205 // ... but they never diverge, so the loop runs forever.
1206 loopInfo.fCount = kLoopTerminationLimit;
1207 }
1208 } else {
1209 // Start never equals end, so the loop will not run a single iteration.
1210 loopInfo.fCount = 0;
1211 }
1212 break;
1213 }
1214 default: SkUNREACHABLE;
Brian Osman77ba8102021-01-12 17:15:30 -05001215 }
1216
John Stiles106e0cd2021-09-07 11:43:51 -04001217 SkASSERT(loopInfo.fCount >= 0);
1218 if (loopInfo.fCount >= kLoopTerminationLimit) {
Brian Osman77ba8102021-01-12 17:15:30 -05001219 return "loop must guarantee termination in fewer iterations";
1220 }
1221
1222 return nullptr; // All checks pass
1223}
1224
John Stiles9c975c52021-08-31 10:18:57 -04001225std::unique_ptr<LoopUnrollInfo> Analysis::GetLoopUnrollInfo(int offset,
1226 const Statement* loopInitializer,
1227 const Expression* loopTest,
1228 const Expression* loopNext,
1229 const Statement* loopStatement,
1230 ErrorReporter* errors) {
1231 auto result = std::make_unique<LoopUnrollInfo>();
1232 if (const char* msg = invalid_for_ES2(offset, loopInitializer, loopTest, loopNext,
1233 loopStatement, *result)) {
1234 result = nullptr;
Brian Osman77ba8102021-01-12 17:15:30 -05001235 if (errors) {
John Stiles232b4ce2021-03-01 22:14:22 -05001236 errors->error(offset, msg);
Brian Osman77ba8102021-01-12 17:15:30 -05001237 }
Brian Osman77ba8102021-01-12 17:15:30 -05001238 }
John Stiles9c975c52021-08-31 10:18:57 -04001239 return result;
Brian Osman77ba8102021-01-12 17:15:30 -05001240}
1241
Brian Osman7b361492021-02-25 11:25:30 -05001242// Checks for ES2 constant-expression rules, and (optionally) constant-index-expression rules
1243// (if loopIndices is non-nullptr)
1244class ConstantExpressionVisitor : public ProgramVisitor {
Brian Osmanea485e52021-01-15 13:20:32 -05001245public:
Brian Osman7b361492021-02-25 11:25:30 -05001246 ConstantExpressionVisitor(const std::set<const Variable*>* loopIndices)
Brian Osmanea485e52021-01-15 13:20:32 -05001247 : fLoopIndices(loopIndices) {}
1248
1249 bool visitExpression(const Expression& e) override {
1250 // A constant-(index)-expression is one of...
1251 switch (e.kind()) {
1252 // ... a literal value
John Stiles7591d4b2021-09-13 13:32:06 -04001253 case Expression::Kind::kLiteral:
Brian Osmanea485e52021-01-15 13:20:32 -05001254 return false;
1255
John Stiles532138c2021-03-04 16:29:22 -05001256 // ... settings can appear in fragment processors; they will resolve when compiled
1257 case Expression::Kind::kSetting:
1258 return false;
1259
Brian Osman7b361492021-02-25 11:25:30 -05001260 // ... a global or local variable qualified as 'const', excluding function parameters.
1261 // ... loop indices as defined in section 4. [constant-index-expression]
1262 case Expression::Kind::kVariableReference: {
1263 const Variable* v = e.as<VariableReference>().variable();
1264 if ((v->storage() == Variable::Storage::kGlobal ||
1265 v->storage() == Variable::Storage::kLocal) &&
1266 (v->modifiers().fFlags & Modifiers::kConst_Flag)) {
1267 return false;
1268 }
1269 return !fLoopIndices || fLoopIndices->find(v) == fLoopIndices->end();
1270 }
Brian Osmanea485e52021-01-15 13:20:32 -05001271
1272 // ... expressions composed of both of the above
1273 case Expression::Kind::kBinary:
John Stiles7384b372021-04-01 13:48:15 -04001274 case Expression::Kind::kConstructorArray:
John Stilese3ae9682021-08-05 10:35:01 -04001275 case Expression::Kind::kConstructorArrayCast:
John Stiles8cad6372021-04-07 12:31:13 -04001276 case Expression::Kind::kConstructorCompound:
1277 case Expression::Kind::kConstructorCompoundCast:
John Stilese1182782021-03-30 22:09:37 -04001278 case Expression::Kind::kConstructorDiagonalMatrix:
John Stiles5abb9e12021-04-06 13:47:19 -04001279 case Expression::Kind::kConstructorMatrixResize:
John Stilesfd7252f2021-04-04 22:24:40 -04001280 case Expression::Kind::kConstructorScalarCast:
John Stiles2938eea2021-04-01 18:58:25 -04001281 case Expression::Kind::kConstructorSplat:
John Stilesd47330f2021-04-08 23:25:52 -04001282 case Expression::Kind::kConstructorStruct:
Brian Osmanea485e52021-01-15 13:20:32 -05001283 case Expression::Kind::kFieldAccess:
1284 case Expression::Kind::kIndex:
1285 case Expression::Kind::kPrefix:
1286 case Expression::Kind::kPostfix:
1287 case Expression::Kind::kSwizzle:
1288 case Expression::Kind::kTernary:
1289 return INHERITED::visitExpression(e);
1290
John Stiles7bd3f1c2021-08-27 16:12:10 -04001291 // Function calls are completely disallowed in SkSL constant-(index)-expressions.
1292 // GLSL does mandate that calling a built-in function where the arguments are all
1293 // constant-expressions should result in a constant-expression. SkSL handles this by
1294 // optimizing fully-constant function calls into literals in FunctionCall::Make.
Brian Osmanea485e52021-01-15 13:20:32 -05001295 case Expression::Kind::kFunctionCall:
John Stiles7bd3f1c2021-08-27 16:12:10 -04001296 case Expression::Kind::kExternalFunctionCall:
1297 case Expression::Kind::kChildCall:
Brian Osmanea485e52021-01-15 13:20:32 -05001298
John Stiles7bd3f1c2021-08-27 16:12:10 -04001299 // These shouldn't appear in a valid program at all, and definitely aren't
1300 // constant-index-expressions.
Ethan Nicholas549c6b82021-06-25 12:31:44 -04001301 case Expression::Kind::kPoison:
John Stiles7bd3f1c2021-08-27 16:12:10 -04001302 case Expression::Kind::kFunctionReference:
1303 case Expression::Kind::kExternalFunctionReference:
Brian Osman3099f792021-09-01 13:12:16 -04001304 case Expression::Kind::kMethodReference:
John Stiles7bd3f1c2021-08-27 16:12:10 -04001305 case Expression::Kind::kTypeReference:
1306 case Expression::Kind::kCodeString:
Ethan Nicholas549c6b82021-06-25 12:31:44 -04001307 return true;
1308
Brian Osmanea485e52021-01-15 13:20:32 -05001309 default:
1310 SkDEBUGFAIL("Unexpected expression type");
1311 return true;
1312 }
1313 }
1314
1315private:
1316 const std::set<const Variable*>* fLoopIndices;
1317 using INHERITED = ProgramVisitor;
1318};
1319
1320class ES2IndexingVisitor : public ProgramVisitor {
1321public:
1322 ES2IndexingVisitor(ErrorReporter& errors) : fErrors(errors) {}
1323
1324 bool visitStatement(const Statement& s) override {
1325 if (s.is<ForStatement>()) {
1326 const ForStatement& f = s.as<ForStatement>();
1327 SkASSERT(f.initializer() && f.initializer()->is<VarDeclaration>());
1328 const Variable* var = &f.initializer()->as<VarDeclaration>().var();
1329 auto [iter, inserted] = fLoopIndices.insert(var);
1330 SkASSERT(inserted);
1331 bool result = this->visitStatement(*f.statement());
1332 fLoopIndices.erase(iter);
1333 return result;
1334 }
1335 return INHERITED::visitStatement(s);
1336 }
1337
1338 bool visitExpression(const Expression& e) override {
1339 if (e.is<IndexExpression>()) {
1340 const IndexExpression& i = e.as<IndexExpression>();
Brian Osman7b361492021-02-25 11:25:30 -05001341 ConstantExpressionVisitor indexerInvalid(&fLoopIndices);
Brian Osmanea485e52021-01-15 13:20:32 -05001342 if (indexerInvalid.visitExpression(*i.index())) {
1343 fErrors.error(i.fOffset, "index expression must be constant");
1344 return true;
1345 }
1346 }
1347 return INHERITED::visitExpression(e);
1348 }
1349
1350 using ProgramVisitor::visitProgramElement;
1351
1352private:
1353 ErrorReporter& fErrors;
1354 std::set<const Variable*> fLoopIndices;
1355 using INHERITED = ProgramVisitor;
1356};
1357
1358
1359void Analysis::ValidateIndexingForES2(const ProgramElement& pe, ErrorReporter& errors) {
1360 ES2IndexingVisitor visitor(errors);
1361 visitor.visitProgramElement(pe);
1362}
1363
Brian Osman7b361492021-02-25 11:25:30 -05001364bool Analysis::IsConstantExpression(const Expression& expr) {
1365 ConstantExpressionVisitor visitor(/*loopIndices=*/nullptr);
1366 return !visitor.visitExpression(expr);
1367}
1368
John Stiles958f4b52021-03-17 16:39:49 -04001369bool Analysis::CanExitWithoutReturningValue(const FunctionDeclaration& funcDecl,
1370 const Statement& body) {
1371 if (funcDecl.returnType().isVoid()) {
1372 return false;
1373 }
John Stilesb3dcbb12021-03-04 16:00:20 -05001374 ReturnsOnAllPathsVisitor visitor;
John Stiles958f4b52021-03-17 16:39:49 -04001375 visitor.visitStatement(body);
John Stilesb3dcbb12021-03-04 16:00:20 -05001376 return !visitor.fFoundReturn;
1377}
1378
John Stiles2ecc5952021-09-01 14:41:36 -04001379void Analysis::VerifyStaticTestsAndExpressions(const Program& program) {
1380 class TestsAndExpressions : public ProgramVisitor {
John Stiles0fc6bed2021-09-01 11:35:59 -04001381 public:
John Stiles2ecc5952021-09-01 14:41:36 -04001382 TestsAndExpressions(const Context& ctx) : fContext(ctx) {}
John Stiles0fc6bed2021-09-01 11:35:59 -04001383
1384 using ProgramVisitor::visitProgramElement;
1385
1386 bool visitStatement(const Statement& stmt) override {
John Stiles2ecc5952021-09-01 14:41:36 -04001387 if (!fContext.fConfig->fSettings.fPermitInvalidStaticTests) {
1388 switch (stmt.kind()) {
1389 case Statement::Kind::kIf:
1390 if (stmt.as<IfStatement>().isStatic()) {
1391 fContext.fErrors->error(stmt.fOffset, "static if has non-static test");
1392 }
1393 break;
John Stiles0fc6bed2021-09-01 11:35:59 -04001394
John Stiles2ecc5952021-09-01 14:41:36 -04001395 case Statement::Kind::kSwitch:
1396 if (stmt.as<SwitchStatement>().isStatic()) {
1397 fContext.fErrors->error(stmt.fOffset,
1398 "static switch has non-static test");
1399 }
1400 break;
John Stiles0fc6bed2021-09-01 11:35:59 -04001401
John Stiles2ecc5952021-09-01 14:41:36 -04001402 default:
1403 break;
1404 }
John Stiles0fc6bed2021-09-01 11:35:59 -04001405 }
1406 return INHERITED::visitStatement(stmt);
1407 }
1408
John Stiles2ecc5952021-09-01 14:41:36 -04001409 bool visitExpression(const Expression& expr) override {
1410 switch (expr.kind()) {
1411 case Expression::Kind::kFunctionCall: {
1412 const FunctionDeclaration& decl = expr.as<FunctionCall>().function();
1413 if (!decl.isBuiltin() && !decl.definition()) {
1414 fContext.fErrors->error(expr.fOffset, "function '" + decl.description() +
1415 "' is not defined");
1416 }
1417 break;
1418 }
1419 case Expression::Kind::kExternalFunctionReference:
1420 case Expression::Kind::kFunctionReference:
Brian Osman3099f792021-09-01 13:12:16 -04001421 case Expression::Kind::kMethodReference:
John Stiles2ecc5952021-09-01 14:41:36 -04001422 case Expression::Kind::kTypeReference:
1423 SkDEBUGFAIL("invalid reference-expr, should have been reported by coerce()");
1424 fContext.fErrors->error(expr.fOffset, "invalid expression");
1425 break;
1426 default:
1427 if (expr.type() == *fContext.fTypes.fInvalid) {
1428 fContext.fErrors->error(expr.fOffset, "invalid expression");
1429 }
1430 break;
1431 }
1432 return INHERITED::visitExpression(expr);
John Stiles0fc6bed2021-09-01 11:35:59 -04001433 }
1434
1435 private:
1436 using INHERITED = ProgramVisitor;
John Stiles2ecc5952021-09-01 14:41:36 -04001437 const Context& fContext;
John Stiles0fc6bed2021-09-01 11:35:59 -04001438 };
1439
John Stiles0fc6bed2021-09-01 11:35:59 -04001440 // Check all of the program's owned elements. (Built-in elements are assumed to be valid.)
John Stiles2ecc5952021-09-01 14:41:36 -04001441 TestsAndExpressions visitor{*program.fContext};
John Stiles0fc6bed2021-09-01 11:35:59 -04001442 for (const std::unique_ptr<ProgramElement>& element : program.ownedElements()) {
John Stiles2ecc5952021-09-01 14:41:36 -04001443 visitor.visitProgramElement(*element);
John Stiles0fc6bed2021-09-01 11:35:59 -04001444 }
1445}
1446
John Stiles49b1a422021-09-22 09:35:39 -04001447void Analysis::EliminateUnreachableCode(std::unique_ptr<Statement>& stmt, ProgramUsage* usage) {
1448 class UnreachableCodeEliminator : public ProgramWriter {
1449 public:
1450 UnreachableCodeEliminator(ProgramUsage* usage)
1451 : fUsage(usage) {
1452 fFoundFunctionExit.push(false);
1453 fFoundLoopExit.push(false);
1454 }
1455
1456 bool visitExpressionPtr(std::unique_ptr<Expression>& expr) override {
1457 // We don't need to look inside expressions at all.
1458 return false;
1459 }
1460
1461 bool visitStatementPtr(std::unique_ptr<Statement>& stmt) override {
1462 if (fFoundFunctionExit.top() || fFoundLoopExit.top()) {
1463 // If we already found an exit in this section, anything beyond it is dead code.
1464 if (!stmt->is<Nop>()) {
1465 // Eliminate the dead statement by substituting a Nop.
1466 if (fUsage) {
1467 fUsage->remove(stmt.get());
1468 }
1469 stmt = std::make_unique<Nop>();
1470 }
1471 return false;
1472 }
1473
1474 switch (stmt->kind()) {
1475 case Statement::Kind::kReturn:
1476 case Statement::Kind::kDiscard:
1477 // We found a function exit on this path.
1478 fFoundFunctionExit.top() = true;
1479 break;
1480
1481 case Statement::Kind::kBreak:
1482 case Statement::Kind::kContinue:
1483 // We found a loop exit on this path. Note that we skip over switch statements
1484 // completely when eliminating code, so any `break` statement would be breaking
1485 // out of a loop, not out of a switch.
1486 fFoundLoopExit.top() = true;
1487 break;
1488
1489 case Statement::Kind::kExpression:
1490 case Statement::Kind::kInlineMarker:
1491 case Statement::Kind::kNop:
1492 case Statement::Kind::kVarDeclaration:
1493 // These statements don't affect control flow.
1494 break;
1495
1496 case Statement::Kind::kBlock:
1497 // Blocks are on the straight-line path and don't affect control flow.
1498 return INHERITED::visitStatementPtr(stmt);
1499
1500 case Statement::Kind::kDo: {
1501 // Function-exits are allowed to propagate outside of a do-loop, because it
1502 // always executes its body at least once.
1503 fFoundLoopExit.push(false);
1504 bool result = INHERITED::visitStatementPtr(stmt);
1505 fFoundLoopExit.pop();
1506 return result;
1507 }
1508 case Statement::Kind::kFor: {
1509 // Function-exits are not allowed to propagate out, because a for-loop or while-
1510 // loop could potentially run zero times.
1511 fFoundFunctionExit.push(false);
1512 fFoundLoopExit.push(false);
1513 bool result = INHERITED::visitStatementPtr(stmt);
1514 fFoundLoopExit.pop();
1515 fFoundFunctionExit.pop();
1516 return result;
1517 }
1518 case Statement::Kind::kIf: {
1519 // This statement is conditional and encloses two inner sections of code.
1520 // If both sides contain a function-exit or loop-exit, that exit is allowed to
1521 // propagate out.
1522 IfStatement& ifStmt = stmt->as<IfStatement>();
1523
1524 fFoundFunctionExit.push(false);
1525 fFoundLoopExit.push(false);
1526 bool result = (ifStmt.ifTrue() && this->visitStatementPtr(ifStmt.ifTrue()));
1527 bool foundFunctionExitOnTrue = fFoundFunctionExit.top();
1528 bool foundLoopExitOnTrue = fFoundLoopExit.top();
1529 fFoundFunctionExit.pop();
1530 fFoundLoopExit.pop();
1531
1532 fFoundFunctionExit.push(false);
1533 fFoundLoopExit.push(false);
1534 result |= (ifStmt.ifFalse() && this->visitStatementPtr(ifStmt.ifFalse()));
1535 bool foundFunctionExitOnFalse = fFoundFunctionExit.top();
1536 bool foundLoopExitOnFalse = fFoundLoopExit.top();
1537 fFoundFunctionExit.pop();
1538 fFoundLoopExit.pop();
1539
1540 fFoundFunctionExit.top() |= foundFunctionExitOnTrue && foundFunctionExitOnFalse;
1541 fFoundLoopExit.top() |= foundLoopExitOnTrue && foundLoopExitOnFalse;
1542 return result;
1543 }
1544 case Statement::Kind::kSwitch:
1545 case Statement::Kind::kSwitchCase:
1546 // We skip past switch statements entirely when scanning for dead code. Their
1547 // control flow is quite complex and we already do a good job of flattening out
1548 // switches on constant values.
1549 break;
1550 }
1551
1552 return false;
1553 }
1554
1555 ProgramUsage* fUsage;
1556 std::stack<bool> fFoundFunctionExit;
1557 std::stack<bool> fFoundLoopExit;
1558
1559 using INHERITED = ProgramWriter;
1560 };
1561
1562 UnreachableCodeEliminator visitor{usage};
1563 visitor.visitStatementPtr(stmt);
1564}
1565
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001566////////////////////////////////////////////////////////////////////////////////
1567// ProgramVisitor
1568
Brian Osman133724c2020-10-28 14:14:39 -04001569bool ProgramVisitor::visit(const Program& program) {
1570 for (const ProgramElement* pe : program.elements()) {
Brian Osman1179fcf2020-10-08 16:04:40 -04001571 if (this->visitProgramElement(*pe)) {
John Stiles933abe32020-08-28 11:58:40 -04001572 return true;
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001573 }
1574 }
John Stiles933abe32020-08-28 11:58:40 -04001575 return false;
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001576}
1577
John Stiles48b25582021-03-11 14:26:42 -05001578template <typename T> bool TProgramVisitor<T>::visitExpression(typename T::Expression& e) {
John Stiles70b82422020-09-30 10:55:12 -04001579 switch (e.kind()) {
Brian Osmanbe0b3b72021-01-06 14:27:35 -05001580 case Expression::Kind::kExternalFunctionReference:
Ethan Nicholase6592142020-09-08 10:22:09 -04001581 case Expression::Kind::kFunctionReference:
John Stiles7591d4b2021-09-13 13:32:06 -04001582 case Expression::Kind::kLiteral:
Brian Osman3099f792021-09-01 13:12:16 -04001583 case Expression::Kind::kMethodReference:
Ethan Nicholas549c6b82021-06-25 12:31:44 -04001584 case Expression::Kind::kPoison:
Ethan Nicholase6592142020-09-08 10:22:09 -04001585 case Expression::Kind::kSetting:
1586 case Expression::Kind::kTypeReference:
1587 case Expression::Kind::kVariableReference:
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001588 // Leaf expressions return false
1589 return false;
John Stiles70b82422020-09-30 10:55:12 -04001590
Ethan Nicholase6592142020-09-08 10:22:09 -04001591 case Expression::Kind::kBinary: {
John Stiles70b82422020-09-30 10:55:12 -04001592 auto& b = e.template as<BinaryExpression>();
John Stiles48b25582021-03-11 14:26:42 -05001593 return (b.left() && this->visitExpressionPtr(b.left())) ||
1594 (b.right() && this->visitExpressionPtr(b.right()));
John Stiles70b82422020-09-30 10:55:12 -04001595 }
Brian Osmaneb0f29d2021-08-04 11:34:16 -04001596 case Expression::Kind::kChildCall: {
1597 // We don't visit the child variable itself, just the arguments
1598 auto& c = e.template as<ChildCall>();
1599 for (auto& arg : c.arguments()) {
1600 if (arg && this->visitExpressionPtr(arg)) { return true; }
1601 }
1602 return false;
1603 }
John Stiles7384b372021-04-01 13:48:15 -04001604 case Expression::Kind::kConstructorArray:
John Stilese3ae9682021-08-05 10:35:01 -04001605 case Expression::Kind::kConstructorArrayCast:
John Stiles8cad6372021-04-07 12:31:13 -04001606 case Expression::Kind::kConstructorCompound:
1607 case Expression::Kind::kConstructorCompoundCast:
John Stiles2938eea2021-04-01 18:58:25 -04001608 case Expression::Kind::kConstructorDiagonalMatrix:
John Stiles5abb9e12021-04-06 13:47:19 -04001609 case Expression::Kind::kConstructorMatrixResize:
John Stilesfd7252f2021-04-04 22:24:40 -04001610 case Expression::Kind::kConstructorScalarCast:
John Stilesd47330f2021-04-08 23:25:52 -04001611 case Expression::Kind::kConstructorSplat:
1612 case Expression::Kind::kConstructorStruct: {
John Stiles7384b372021-04-01 13:48:15 -04001613 auto& c = e.asAnyConstructor();
1614 for (auto& arg : c.argumentSpan()) {
John Stiles48b25582021-03-11 14:26:42 -05001615 if (this->visitExpressionPtr(arg)) { return true; }
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001616 }
John Stiles70b82422020-09-30 10:55:12 -04001617 return false;
1618 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001619 case Expression::Kind::kExternalFunctionCall: {
John Stiles70b82422020-09-30 10:55:12 -04001620 auto& c = e.template as<ExternalFunctionCall>();
Ethan Nicholas6e86ec92020-09-30 14:29:56 -04001621 for (auto& arg : c.arguments()) {
John Stiles48b25582021-03-11 14:26:42 -05001622 if (this->visitExpressionPtr(arg)) { return true; }
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001623 }
John Stiles70b82422020-09-30 10:55:12 -04001624 return false;
1625 }
John Stilesd7ab4502020-09-24 22:41:00 -04001626 case Expression::Kind::kFieldAccess:
John Stiles48b25582021-03-11 14:26:42 -05001627 return this->visitExpressionPtr(e.template as<FieldAccess>().base());
John Stiles70b82422020-09-30 10:55:12 -04001628
Ethan Nicholase6592142020-09-08 10:22:09 -04001629 case Expression::Kind::kFunctionCall: {
John Stiles70b82422020-09-30 10:55:12 -04001630 auto& c = e.template as<FunctionCall>();
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001631 for (auto& arg : c.arguments()) {
John Stiles48b25582021-03-11 14:26:42 -05001632 if (arg && this->visitExpressionPtr(arg)) { return true; }
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001633 }
John Stiles70b82422020-09-30 10:55:12 -04001634 return false;
1635 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001636 case Expression::Kind::kIndex: {
John Stiles70b82422020-09-30 10:55:12 -04001637 auto& i = e.template as<IndexExpression>();
John Stiles48b25582021-03-11 14:26:42 -05001638 return this->visitExpressionPtr(i.base()) || this->visitExpressionPtr(i.index());
John Stiles70b82422020-09-30 10:55:12 -04001639 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001640 case Expression::Kind::kPostfix:
John Stiles48b25582021-03-11 14:26:42 -05001641 return this->visitExpressionPtr(e.template as<PostfixExpression>().operand());
John Stiles70b82422020-09-30 10:55:12 -04001642
Ethan Nicholase6592142020-09-08 10:22:09 -04001643 case Expression::Kind::kPrefix:
John Stiles48b25582021-03-11 14:26:42 -05001644 return this->visitExpressionPtr(e.template as<PrefixExpression>().operand());
John Stiles70b82422020-09-30 10:55:12 -04001645
Brian Osman010ce6a2020-10-19 16:34:10 -04001646 case Expression::Kind::kSwizzle: {
1647 auto& s = e.template as<Swizzle>();
John Stiles48b25582021-03-11 14:26:42 -05001648 return s.base() && this->visitExpressionPtr(s.base());
Brian Osman010ce6a2020-10-19 16:34:10 -04001649 }
John Stiles70b82422020-09-30 10:55:12 -04001650
Ethan Nicholase6592142020-09-08 10:22:09 -04001651 case Expression::Kind::kTernary: {
John Stiles70b82422020-09-30 10:55:12 -04001652 auto& t = e.template as<TernaryExpression>();
John Stiles48b25582021-03-11 14:26:42 -05001653 return this->visitExpressionPtr(t.test()) ||
1654 (t.ifTrue() && this->visitExpressionPtr(t.ifTrue())) ||
1655 (t.ifFalse() && this->visitExpressionPtr(t.ifFalse()));
John Stiles70b82422020-09-30 10:55:12 -04001656 }
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001657 default:
1658 SkUNREACHABLE;
1659 }
1660}
1661
John Stiles48b25582021-03-11 14:26:42 -05001662template <typename T> bool TProgramVisitor<T>::visitStatement(typename T::Statement& s) {
John Stiles70b82422020-09-30 10:55:12 -04001663 switch (s.kind()) {
Ethan Nicholase6592142020-09-08 10:22:09 -04001664 case Statement::Kind::kBreak:
1665 case Statement::Kind::kContinue:
1666 case Statement::Kind::kDiscard:
John Stiles98c1f822020-09-09 14:18:53 -04001667 case Statement::Kind::kInlineMarker:
Ethan Nicholase6592142020-09-08 10:22:09 -04001668 case Statement::Kind::kNop:
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001669 // Leaf statements just return false
1670 return false;
John Stiles70b82422020-09-30 10:55:12 -04001671
Ethan Nicholase6592142020-09-08 10:22:09 -04001672 case Statement::Kind::kBlock:
John Stiles70b82422020-09-30 10:55:12 -04001673 for (auto& stmt : s.template as<Block>().children()) {
John Stiles48b25582021-03-11 14:26:42 -05001674 if (stmt && this->visitStatementPtr(stmt)) {
Ethan Nicholas7bd60432020-09-25 14:31:59 -04001675 return true;
1676 }
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001677 }
1678 return false;
John Stiles70b82422020-09-30 10:55:12 -04001679
John Stilesa0e56e32021-03-03 13:14:37 -05001680 case Statement::Kind::kSwitchCase: {
1681 auto& sc = s.template as<SwitchCase>();
John Stiles48b25582021-03-11 14:26:42 -05001682 if (sc.value() && this->visitExpressionPtr(sc.value())) {
John Stilesa0e56e32021-03-03 13:14:37 -05001683 return true;
1684 }
John Stiles48b25582021-03-11 14:26:42 -05001685 return this->visitStatementPtr(sc.statement());
John Stilesa0e56e32021-03-03 13:14:37 -05001686 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001687 case Statement::Kind::kDo: {
John Stiles70b82422020-09-30 10:55:12 -04001688 auto& d = s.template as<DoStatement>();
John Stiles48b25582021-03-11 14:26:42 -05001689 return this->visitExpressionPtr(d.test()) || this->visitStatementPtr(d.statement());
John Stiles70b82422020-09-30 10:55:12 -04001690 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001691 case Statement::Kind::kExpression:
John Stiles48b25582021-03-11 14:26:42 -05001692 return this->visitExpressionPtr(s.template as<ExpressionStatement>().expression());
John Stiles70b82422020-09-30 10:55:12 -04001693
Ethan Nicholase6592142020-09-08 10:22:09 -04001694 case Statement::Kind::kFor: {
John Stiles70b82422020-09-30 10:55:12 -04001695 auto& f = s.template as<ForStatement>();
John Stiles48b25582021-03-11 14:26:42 -05001696 return (f.initializer() && this->visitStatementPtr(f.initializer())) ||
1697 (f.test() && this->visitExpressionPtr(f.test())) ||
1698 (f.next() && this->visitExpressionPtr(f.next())) ||
1699 this->visitStatementPtr(f.statement());
John Stiles70b82422020-09-30 10:55:12 -04001700 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001701 case Statement::Kind::kIf: {
John Stiles70b82422020-09-30 10:55:12 -04001702 auto& i = s.template as<IfStatement>();
John Stiles48b25582021-03-11 14:26:42 -05001703 return (i.test() && this->visitExpressionPtr(i.test())) ||
1704 (i.ifTrue() && this->visitStatementPtr(i.ifTrue())) ||
1705 (i.ifFalse() && this->visitStatementPtr(i.ifFalse()));
John Stiles70b82422020-09-30 10:55:12 -04001706 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001707 case Statement::Kind::kReturn: {
John Stiles70b82422020-09-30 10:55:12 -04001708 auto& r = s.template as<ReturnStatement>();
John Stiles48b25582021-03-11 14:26:42 -05001709 return r.expression() && this->visitExpressionPtr(r.expression());
John Stiles70b82422020-09-30 10:55:12 -04001710 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001711 case Statement::Kind::kSwitch: {
John Stiles70b82422020-09-30 10:55:12 -04001712 auto& sw = s.template as<SwitchStatement>();
John Stiles48b25582021-03-11 14:26:42 -05001713 if (this->visitExpressionPtr(sw.value())) {
John Stiles70b82422020-09-30 10:55:12 -04001714 return true;
1715 }
John Stiles48b25582021-03-11 14:26:42 -05001716 for (auto& c : sw.cases()) {
1717 if (this->visitStatementPtr(c)) {
John Stiles70b82422020-09-30 10:55:12 -04001718 return true;
1719 }
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001720 }
John Stiles70b82422020-09-30 10:55:12 -04001721 return false;
1722 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001723 case Statement::Kind::kVarDeclaration: {
John Stiles70b82422020-09-30 10:55:12 -04001724 auto& v = s.template as<VarDeclaration>();
John Stiles48b25582021-03-11 14:26:42 -05001725 return v.value() && this->visitExpressionPtr(v.value());
John Stiles70b82422020-09-30 10:55:12 -04001726 }
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001727 default:
1728 SkUNREACHABLE;
1729 }
1730}
1731
John Stiles48b25582021-03-11 14:26:42 -05001732template <typename T> bool TProgramVisitor<T>::visitProgramElement(typename T::ProgramElement& pe) {
John Stiles70b82422020-09-30 10:55:12 -04001733 switch (pe.kind()) {
Ethan Nicholase6592142020-09-08 10:22:09 -04001734 case ProgramElement::Kind::kExtension:
John Stiles569249b2020-11-03 12:18:22 -05001735 case ProgramElement::Kind::kFunctionPrototype:
John Stilesd39aec02020-12-03 10:42:26 -05001736 case ProgramElement::Kind::kInterfaceBlock:
Ethan Nicholase6592142020-09-08 10:22:09 -04001737 case ProgramElement::Kind::kModifiers:
John Stilesdc75a972020-11-25 16:24:55 -05001738 case ProgramElement::Kind::kStructDefinition:
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001739 // Leaf program elements just return false by default
1740 return false;
John Stiles70b82422020-09-30 10:55:12 -04001741
Ethan Nicholase6592142020-09-08 10:22:09 -04001742 case ProgramElement::Kind::kFunction:
John Stiles48b25582021-03-11 14:26:42 -05001743 return this->visitStatementPtr(pe.template as<FunctionDefinition>().body());
John Stiles70b82422020-09-30 10:55:12 -04001744
Brian Osmanc0213602020-10-06 14:43:32 -04001745 case ProgramElement::Kind::kGlobalVar:
John Stiles48b25582021-03-11 14:26:42 -05001746 return this->visitStatementPtr(pe.template as<GlobalVarDeclaration>().declaration());
John Stiles70b82422020-09-30 10:55:12 -04001747
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001748 default:
1749 SkUNREACHABLE;
1750 }
1751}
1752
John Stiles48b25582021-03-11 14:26:42 -05001753template class TProgramVisitor<ProgramVisitorTypes>;
1754template class TProgramVisitor<ProgramWriterTypes>;
John Stiles70b82422020-09-30 10:55:12 -04001755
John Stilesa6841be2020-08-06 14:11:56 -04001756} // namespace SkSL