blob: 6a98b64694c7c5fbceb2a5ad9d122a97c06f2533 [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)) {
Ethan Nicholas89cfde12021-09-27 11:20:34 -0400320 fErrors->error(expr.fLine,
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:
Ethan Nicholas89cfde12021-09-27 11:20:34 -0400346 fErrors->error(expr.fLine, "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) {
Ethan Nicholas89cfde12021-09-27 11:20:34 -0400358 fErrors->error(swizzle.fLine,
John Stilesa976da72020-09-25 23:06:26 -0400359 "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;
Ethan Nicholas89cfde12021-09-27 11:20:34 -0400655 fContext.fErrors->error(pe.fLine, 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();
Ethan Nicholas89cfde12021-09-27 11:20:34 -0400671 fContext.fErrors->error(pe.fLine, std::move(msg));
John Stiles2af4b132021-09-02 16:17:07 -0400672 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()) {
Ethan Nicholas89cfde12021-09-27 11:20:34 -0400783 context.fErrors->error(/*line=*/-1, "program is too large");
John Stiles6475b102021-09-02 14:09:23 -0400784 }
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) {
Ethan Nicholas89cfde12021-09-27 11:20:34 -0400818 errors->error(stmt.fLine, "variable '" + var->name() + "' must be created in a scope");
Ethan Nicholas98eae1e2021-09-01 14:37:29 -0400819 }
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) {
Ethan Nicholas89cfde12021-09-27 11:20:34 -0400922 errors->error(expr->fLine, "can't assign to expression '" + expr->description() + "'");
John Stilesbb8cf582021-08-26 23:34:59 -0400923 }
John Stiles516704b2021-02-26 15:01:57 -0500924 return false;
925 }
926 info.fAssignedVar->setRefKind(kind);
927 return true;
928}
929
John Stilesc30fbca2020-11-19 16:25:49 -0500930bool Analysis::IsTrivialExpression(const Expression& expr) {
John Stiles7591d4b2021-09-13 13:32:06 -0400931 return expr.is<Literal>() ||
John Stilesc30fbca2020-11-19 16:25:49 -0500932 expr.is<VariableReference>() ||
933 (expr.is<Swizzle>() &&
934 IsTrivialExpression(*expr.as<Swizzle>().base())) ||
935 (expr.is<FieldAccess>() &&
936 IsTrivialExpression(*expr.as<FieldAccess>().base())) ||
John Stiles2938eea2021-04-01 18:58:25 -0400937 (expr.isAnyConstructor() &&
938 expr.asAnyConstructor().argumentSpan().size() == 1 &&
939 IsTrivialExpression(*expr.asAnyConstructor().argumentSpan().front())) ||
940 (expr.isAnyConstructor() &&
John Stilesc30fbca2020-11-19 16:25:49 -0500941 expr.isConstantOrUniform()) ||
942 (expr.is<IndexExpression>() &&
John Stiles7591d4b2021-09-13 13:32:06 -0400943 expr.as<IndexExpression>().index()->isIntLiteral() &&
John Stilesc30fbca2020-11-19 16:25:49 -0500944 IsTrivialExpression(*expr.as<IndexExpression>().base()));
945}
946
John Stiles5676c572021-03-08 17:10:52 -0500947bool Analysis::IsSameExpressionTree(const Expression& left, const Expression& right) {
John Stiles95d0bad2021-03-01 17:02:28 -0500948 if (left.kind() != right.kind() || left.type() != right.type()) {
949 return false;
950 }
951
John Stiles5676c572021-03-08 17:10:52 -0500952 // This isn't a fully exhaustive list of expressions by any stretch of the imagination; for
953 // instance, `x[y+1] = x[y+1]` isn't detected because we don't look at BinaryExpressions.
954 // Since this is intended to be used for optimization purposes, handling the common cases is
955 // sufficient.
John Stiles95d0bad2021-03-01 17:02:28 -0500956 switch (left.kind()) {
John Stiles7591d4b2021-09-13 13:32:06 -0400957 case Expression::Kind::kLiteral:
958 return left.as<Literal>().value() == right.as<Literal>().value();
John Stiles5676c572021-03-08 17:10:52 -0500959
John Stiles7384b372021-04-01 13:48:15 -0400960 case Expression::Kind::kConstructorArray:
John Stilese3ae9682021-08-05 10:35:01 -0400961 case Expression::Kind::kConstructorArrayCast:
John Stiles8cad6372021-04-07 12:31:13 -0400962 case Expression::Kind::kConstructorCompound:
963 case Expression::Kind::kConstructorCompoundCast:
John Stiles2938eea2021-04-01 18:58:25 -0400964 case Expression::Kind::kConstructorDiagonalMatrix:
John Stiles5abb9e12021-04-06 13:47:19 -0400965 case Expression::Kind::kConstructorMatrixResize:
John Stilesfd7252f2021-04-04 22:24:40 -0400966 case Expression::Kind::kConstructorScalarCast:
John Stilesd47330f2021-04-08 23:25:52 -0400967 case Expression::Kind::kConstructorStruct:
John Stiles268a73f2021-04-07 12:30:22 -0400968 case Expression::Kind::kConstructorSplat: {
John Stilesfd7252f2021-04-04 22:24:40 -0400969 if (left.kind() != right.kind()) {
970 return false;
971 }
John Stiles7384b372021-04-01 13:48:15 -0400972 const AnyConstructor& leftCtor = left.asAnyConstructor();
973 const AnyConstructor& rightCtor = right.asAnyConstructor();
974 const auto leftSpan = leftCtor.argumentSpan();
975 const auto rightSpan = rightCtor.argumentSpan();
976 if (leftSpan.size() != rightSpan.size()) {
John Stiles5676c572021-03-08 17:10:52 -0500977 return false;
978 }
John Stiles7384b372021-04-01 13:48:15 -0400979 for (size_t index = 0; index < leftSpan.size(); ++index) {
980 if (!IsSameExpressionTree(*leftSpan[index], *rightSpan[index])) {
John Stiles5676c572021-03-08 17:10:52 -0500981 return false;
982 }
983 }
984 return true;
985 }
John Stiles95d0bad2021-03-01 17:02:28 -0500986 case Expression::Kind::kFieldAccess:
987 return left.as<FieldAccess>().fieldIndex() == right.as<FieldAccess>().fieldIndex() &&
John Stiles5676c572021-03-08 17:10:52 -0500988 IsSameExpressionTree(*left.as<FieldAccess>().base(),
989 *right.as<FieldAccess>().base());
John Stiles95d0bad2021-03-01 17:02:28 -0500990
991 case Expression::Kind::kIndex:
John Stiles5676c572021-03-08 17:10:52 -0500992 return IsSameExpressionTree(*left.as<IndexExpression>().index(),
993 *right.as<IndexExpression>().index()) &&
994 IsSameExpressionTree(*left.as<IndexExpression>().base(),
995 *right.as<IndexExpression>().base());
John Stiles95d0bad2021-03-01 17:02:28 -0500996
997 case Expression::Kind::kSwizzle:
998 return left.as<Swizzle>().components() == right.as<Swizzle>().components() &&
John Stiles5676c572021-03-08 17:10:52 -0500999 IsSameExpressionTree(*left.as<Swizzle>().base(), *right.as<Swizzle>().base());
John Stiles95d0bad2021-03-01 17:02:28 -05001000
1001 case Expression::Kind::kVariableReference:
1002 return left.as<VariableReference>().variable() ==
1003 right.as<VariableReference>().variable();
1004
1005 default:
1006 return false;
1007 }
1008}
1009
Ethan Nicholas89cfde12021-09-27 11:20:34 -04001010static const char* invalid_for_ES2(int line,
John Stiles232b4ce2021-03-01 22:14:22 -05001011 const Statement* loopInitializer,
1012 const Expression* loopTest,
1013 const Expression* loopNext,
1014 const Statement* loopStatement,
John Stiles9c975c52021-08-31 10:18:57 -04001015 LoopUnrollInfo& loopInfo) {
Brian Osman77ba8102021-01-12 17:15:30 -05001016 //
1017 // init_declaration has the form: type_specifier identifier = constant_expression
1018 //
John Stiles232b4ce2021-03-01 22:14:22 -05001019 if (!loopInitializer) {
Brian Osman77ba8102021-01-12 17:15:30 -05001020 return "missing init declaration";
1021 }
John Stiles232b4ce2021-03-01 22:14:22 -05001022 if (!loopInitializer->is<VarDeclaration>()) {
Brian Osman77ba8102021-01-12 17:15:30 -05001023 return "invalid init declaration";
1024 }
John Stiles232b4ce2021-03-01 22:14:22 -05001025 const VarDeclaration& initDecl = loopInitializer->as<VarDeclaration>();
Brian Osman6c7910e2021-01-14 09:50:52 -05001026 if (!initDecl.baseType().isNumber()) {
Brian Osman77ba8102021-01-12 17:15:30 -05001027 return "invalid type for loop index";
1028 }
1029 if (initDecl.arraySize() != 0) {
1030 return "invalid type for loop index";
1031 }
1032 if (!initDecl.value()) {
1033 return "missing loop index initializer";
1034 }
Brian Osman448b2d52021-09-23 11:36:15 -04001035 if (!ConstantFolder::GetConstantValue(*initDecl.value(), &loopInfo.fStart)) {
Brian Osman77ba8102021-01-12 17:15:30 -05001036 return "loop index initializer must be a constant expression";
1037 }
1038
1039 loopInfo.fIndex = &initDecl.var();
1040
1041 auto is_loop_index = [&](const std::unique_ptr<Expression>& expr) {
1042 return expr->is<VariableReference>() &&
1043 expr->as<VariableReference>().variable() == loopInfo.fIndex;
1044 };
1045
1046 //
1047 // condition has the form: loop_index relational_operator constant_expression
1048 //
John Stiles232b4ce2021-03-01 22:14:22 -05001049 if (!loopTest) {
Brian Osman77ba8102021-01-12 17:15:30 -05001050 return "missing condition";
1051 }
John Stiles232b4ce2021-03-01 22:14:22 -05001052 if (!loopTest->is<BinaryExpression>()) {
Brian Osman77ba8102021-01-12 17:15:30 -05001053 return "invalid condition";
1054 }
John Stiles232b4ce2021-03-01 22:14:22 -05001055 const BinaryExpression& cond = loopTest->as<BinaryExpression>();
Brian Osman77ba8102021-01-12 17:15:30 -05001056 if (!is_loop_index(cond.left())) {
1057 return "expected loop index on left hand side of condition";
1058 }
1059 // relational_operator is one of: > >= < <= == or !=
John Stiles45990502021-02-16 10:55:27 -05001060 switch (cond.getOperator().kind()) {
Brian Osman77ba8102021-01-12 17:15:30 -05001061 case Token::Kind::TK_GT:
1062 case Token::Kind::TK_GTEQ:
1063 case Token::Kind::TK_LT:
1064 case Token::Kind::TK_LTEQ:
1065 case Token::Kind::TK_EQEQ:
1066 case Token::Kind::TK_NEQ:
1067 break;
1068 default:
1069 return "invalid relational operator";
1070 }
1071 double loopEnd = 0;
Brian Osman448b2d52021-09-23 11:36:15 -04001072 if (!ConstantFolder::GetConstantValue(*cond.right(), &loopEnd)) {
Brian Osman77ba8102021-01-12 17:15:30 -05001073 return "loop index must be compared with a constant expression";
1074 }
1075
1076 //
1077 // expression has one of the following forms:
1078 // loop_index++
1079 // loop_index--
1080 // loop_index += constant_expression
1081 // loop_index -= constant_expression
1082 // The spec doesn't mention prefix increment and decrement, but there is some consensus that
1083 // it's an oversight, so we allow those as well.
1084 //
John Stiles232b4ce2021-03-01 22:14:22 -05001085 if (!loopNext) {
Brian Osman77ba8102021-01-12 17:15:30 -05001086 return "missing loop expression";
1087 }
John Stiles232b4ce2021-03-01 22:14:22 -05001088 switch (loopNext->kind()) {
Brian Osman77ba8102021-01-12 17:15:30 -05001089 case Expression::Kind::kBinary: {
John Stiles232b4ce2021-03-01 22:14:22 -05001090 const BinaryExpression& next = loopNext->as<BinaryExpression>();
Brian Osman77ba8102021-01-12 17:15:30 -05001091 if (!is_loop_index(next.left())) {
1092 return "expected loop index in loop expression";
1093 }
Brian Osman448b2d52021-09-23 11:36:15 -04001094 if (!ConstantFolder::GetConstantValue(*next.right(), &loopInfo.fDelta)) {
Brian Osman77ba8102021-01-12 17:15:30 -05001095 return "loop index must be modified by a constant expression";
1096 }
John Stiles45990502021-02-16 10:55:27 -05001097 switch (next.getOperator().kind()) {
Brian Osman77ba8102021-01-12 17:15:30 -05001098 case Token::Kind::TK_PLUSEQ: break;
1099 case Token::Kind::TK_MINUSEQ: loopInfo.fDelta = -loopInfo.fDelta; break;
1100 default:
1101 return "invalid operator in loop expression";
1102 }
1103 } break;
1104 case Expression::Kind::kPrefix: {
John Stiles232b4ce2021-03-01 22:14:22 -05001105 const PrefixExpression& next = loopNext->as<PrefixExpression>();
Brian Osman77ba8102021-01-12 17:15:30 -05001106 if (!is_loop_index(next.operand())) {
1107 return "expected loop index in loop expression";
1108 }
John Stiles45990502021-02-16 10:55:27 -05001109 switch (next.getOperator().kind()) {
Brian Osman77ba8102021-01-12 17:15:30 -05001110 case Token::Kind::TK_PLUSPLUS: loopInfo.fDelta = 1; break;
1111 case Token::Kind::TK_MINUSMINUS: loopInfo.fDelta = -1; break;
1112 default:
1113 return "invalid operator in loop expression";
1114 }
1115 } break;
1116 case Expression::Kind::kPostfix: {
John Stiles232b4ce2021-03-01 22:14:22 -05001117 const PostfixExpression& next = loopNext->as<PostfixExpression>();
Brian Osman77ba8102021-01-12 17:15:30 -05001118 if (!is_loop_index(next.operand())) {
1119 return "expected loop index in loop expression";
1120 }
John Stiles45990502021-02-16 10:55:27 -05001121 switch (next.getOperator().kind()) {
Brian Osman77ba8102021-01-12 17:15:30 -05001122 case Token::Kind::TK_PLUSPLUS: loopInfo.fDelta = 1; break;
1123 case Token::Kind::TK_MINUSMINUS: loopInfo.fDelta = -1; break;
1124 default:
1125 return "invalid operator in loop expression";
1126 }
1127 } break;
1128 default:
1129 return "invalid loop expression";
1130 }
1131
1132 //
1133 // Within the body of the loop, the loop index is not statically assigned to, nor is it used as
1134 // argument to a function 'out' or 'inout' parameter.
1135 //
John Stiles232b4ce2021-03-01 22:14:22 -05001136 if (Analysis::StatementWritesToVariable(*loopStatement, initDecl.var())) {
Brian Osman77ba8102021-01-12 17:15:30 -05001137 return "loop index must not be modified within body of the loop";
1138 }
1139
1140 // Finally, compute the iteration count, based on the bounds, and the termination operator.
John Stiles106e0cd2021-09-07 11:43:51 -04001141 static constexpr int kLoopTerminationLimit = 100000;
Brian Osman77ba8102021-01-12 17:15:30 -05001142 loopInfo.fCount = 0;
1143
John Stiles106e0cd2021-09-07 11:43:51 -04001144 auto calculateCount = [](double start, double end, double delta,
1145 bool forwards, bool inclusive) -> int {
1146 if (forwards != (start < end)) {
1147 // The loop starts in a completed state (the start has already advanced past the end).
1148 return 0;
Brian Osman77ba8102021-01-12 17:15:30 -05001149 }
John Stiles106e0cd2021-09-07 11:43:51 -04001150 if ((delta == 0.0) || forwards != (delta > 0.0)) {
1151 // The loop does not progress toward a completed state, and will never terminate.
1152 return kLoopTerminationLimit;
1153 }
1154 double iterations = sk_ieee_double_divide(end - start, delta);
1155 double count = std::ceil(iterations);
1156 if (inclusive && (count == iterations)) {
1157 count += 1.0;
1158 }
1159 if (count > kLoopTerminationLimit || !std::isfinite(count)) {
1160 // The loop runs for more iterations than we can safely unroll.
1161 return kLoopTerminationLimit;
1162 }
1163 return (int)count;
Brian Osman77ba8102021-01-12 17:15:30 -05001164 };
1165
John Stiles106e0cd2021-09-07 11:43:51 -04001166 switch (cond.getOperator().kind()) {
1167 case Token::Kind::TK_LT:
1168 loopInfo.fCount = calculateCount(loopInfo.fStart, loopEnd, loopInfo.fDelta,
1169 /*forwards=*/true, /*inclusive=*/false);
1170 break;
1171
1172 case Token::Kind::TK_GT:
1173 loopInfo.fCount = calculateCount(loopInfo.fStart, loopEnd, loopInfo.fDelta,
1174 /*forwards=*/false, /*inclusive=*/false);
1175 break;
1176
1177 case Token::Kind::TK_LTEQ:
1178 loopInfo.fCount = calculateCount(loopInfo.fStart, loopEnd, loopInfo.fDelta,
1179 /*forwards=*/true, /*inclusive=*/true);
1180 break;
1181
1182 case Token::Kind::TK_GTEQ:
1183 loopInfo.fCount = calculateCount(loopInfo.fStart, loopEnd, loopInfo.fDelta,
1184 /*forwards=*/false, /*inclusive=*/true);
1185 break;
1186
1187 case Token::Kind::TK_NEQ: {
1188 float iterations = sk_ieee_double_divide(loopEnd - loopInfo.fStart, loopInfo.fDelta);
1189 loopInfo.fCount = std::ceil(iterations);
1190 if (loopInfo.fCount < 0 || loopInfo.fCount != iterations ||
1191 !std::isfinite(iterations)) {
1192 // The loop doesn't reach the exact endpoint and so will never terminate.
1193 loopInfo.fCount = kLoopTerminationLimit;
1194 }
Brian Osman77ba8102021-01-12 17:15:30 -05001195 break;
1196 }
John Stiles106e0cd2021-09-07 11:43:51 -04001197 case Token::Kind::TK_EQEQ: {
1198 if (loopInfo.fStart == loopEnd) {
1199 // Start and end begin in the same place, so we can run one iteration...
1200 if (loopInfo.fDelta) {
1201 // ... and then they diverge, so the loop terminates.
1202 loopInfo.fCount = 1;
1203 } else {
1204 // ... but they never diverge, so the loop runs forever.
1205 loopInfo.fCount = kLoopTerminationLimit;
1206 }
1207 } else {
1208 // Start never equals end, so the loop will not run a single iteration.
1209 loopInfo.fCount = 0;
1210 }
1211 break;
1212 }
1213 default: SkUNREACHABLE;
Brian Osman77ba8102021-01-12 17:15:30 -05001214 }
1215
John Stiles106e0cd2021-09-07 11:43:51 -04001216 SkASSERT(loopInfo.fCount >= 0);
1217 if (loopInfo.fCount >= kLoopTerminationLimit) {
Brian Osman77ba8102021-01-12 17:15:30 -05001218 return "loop must guarantee termination in fewer iterations";
1219 }
1220
1221 return nullptr; // All checks pass
1222}
1223
Ethan Nicholas89cfde12021-09-27 11:20:34 -04001224std::unique_ptr<LoopUnrollInfo> Analysis::GetLoopUnrollInfo(int line,
John Stiles9c975c52021-08-31 10:18:57 -04001225 const Statement* loopInitializer,
1226 const Expression* loopTest,
1227 const Expression* loopNext,
1228 const Statement* loopStatement,
1229 ErrorReporter* errors) {
1230 auto result = std::make_unique<LoopUnrollInfo>();
Ethan Nicholas89cfde12021-09-27 11:20:34 -04001231 if (const char* msg = invalid_for_ES2(line, loopInitializer, loopTest, loopNext,
John Stiles9c975c52021-08-31 10:18:57 -04001232 loopStatement, *result)) {
1233 result = nullptr;
Brian Osman77ba8102021-01-12 17:15:30 -05001234 if (errors) {
Ethan Nicholas89cfde12021-09-27 11:20:34 -04001235 errors->error(line, msg);
Brian Osman77ba8102021-01-12 17:15:30 -05001236 }
Brian Osman77ba8102021-01-12 17:15:30 -05001237 }
John Stiles9c975c52021-08-31 10:18:57 -04001238 return result;
Brian Osman77ba8102021-01-12 17:15:30 -05001239}
1240
Brian Osman7b361492021-02-25 11:25:30 -05001241// Checks for ES2 constant-expression rules, and (optionally) constant-index-expression rules
1242// (if loopIndices is non-nullptr)
1243class ConstantExpressionVisitor : public ProgramVisitor {
Brian Osmanea485e52021-01-15 13:20:32 -05001244public:
Brian Osman7b361492021-02-25 11:25:30 -05001245 ConstantExpressionVisitor(const std::set<const Variable*>* loopIndices)
Brian Osmanea485e52021-01-15 13:20:32 -05001246 : fLoopIndices(loopIndices) {}
1247
1248 bool visitExpression(const Expression& e) override {
1249 // A constant-(index)-expression is one of...
1250 switch (e.kind()) {
1251 // ... a literal value
John Stiles7591d4b2021-09-13 13:32:06 -04001252 case Expression::Kind::kLiteral:
Brian Osmanea485e52021-01-15 13:20:32 -05001253 return false;
1254
John Stiles532138c2021-03-04 16:29:22 -05001255 // ... settings can appear in fragment processors; they will resolve when compiled
1256 case Expression::Kind::kSetting:
1257 return false;
1258
Brian Osman7b361492021-02-25 11:25:30 -05001259 // ... a global or local variable qualified as 'const', excluding function parameters.
1260 // ... loop indices as defined in section 4. [constant-index-expression]
1261 case Expression::Kind::kVariableReference: {
1262 const Variable* v = e.as<VariableReference>().variable();
1263 if ((v->storage() == Variable::Storage::kGlobal ||
1264 v->storage() == Variable::Storage::kLocal) &&
1265 (v->modifiers().fFlags & Modifiers::kConst_Flag)) {
1266 return false;
1267 }
1268 return !fLoopIndices || fLoopIndices->find(v) == fLoopIndices->end();
1269 }
Brian Osmanea485e52021-01-15 13:20:32 -05001270
1271 // ... expressions composed of both of the above
1272 case Expression::Kind::kBinary:
John Stiles7384b372021-04-01 13:48:15 -04001273 case Expression::Kind::kConstructorArray:
John Stilese3ae9682021-08-05 10:35:01 -04001274 case Expression::Kind::kConstructorArrayCast:
John Stiles8cad6372021-04-07 12:31:13 -04001275 case Expression::Kind::kConstructorCompound:
1276 case Expression::Kind::kConstructorCompoundCast:
John Stilese1182782021-03-30 22:09:37 -04001277 case Expression::Kind::kConstructorDiagonalMatrix:
John Stiles5abb9e12021-04-06 13:47:19 -04001278 case Expression::Kind::kConstructorMatrixResize:
John Stilesfd7252f2021-04-04 22:24:40 -04001279 case Expression::Kind::kConstructorScalarCast:
John Stiles2938eea2021-04-01 18:58:25 -04001280 case Expression::Kind::kConstructorSplat:
John Stilesd47330f2021-04-08 23:25:52 -04001281 case Expression::Kind::kConstructorStruct:
Brian Osmanea485e52021-01-15 13:20:32 -05001282 case Expression::Kind::kFieldAccess:
1283 case Expression::Kind::kIndex:
1284 case Expression::Kind::kPrefix:
1285 case Expression::Kind::kPostfix:
1286 case Expression::Kind::kSwizzle:
1287 case Expression::Kind::kTernary:
1288 return INHERITED::visitExpression(e);
1289
John Stiles7bd3f1c2021-08-27 16:12:10 -04001290 // Function calls are completely disallowed in SkSL constant-(index)-expressions.
1291 // GLSL does mandate that calling a built-in function where the arguments are all
1292 // constant-expressions should result in a constant-expression. SkSL handles this by
1293 // optimizing fully-constant function calls into literals in FunctionCall::Make.
Brian Osmanea485e52021-01-15 13:20:32 -05001294 case Expression::Kind::kFunctionCall:
John Stiles7bd3f1c2021-08-27 16:12:10 -04001295 case Expression::Kind::kExternalFunctionCall:
1296 case Expression::Kind::kChildCall:
Brian Osmanea485e52021-01-15 13:20:32 -05001297
John Stiles7bd3f1c2021-08-27 16:12:10 -04001298 // These shouldn't appear in a valid program at all, and definitely aren't
1299 // constant-index-expressions.
Ethan Nicholas549c6b82021-06-25 12:31:44 -04001300 case Expression::Kind::kPoison:
John Stiles7bd3f1c2021-08-27 16:12:10 -04001301 case Expression::Kind::kFunctionReference:
1302 case Expression::Kind::kExternalFunctionReference:
Brian Osman3099f792021-09-01 13:12:16 -04001303 case Expression::Kind::kMethodReference:
John Stiles7bd3f1c2021-08-27 16:12:10 -04001304 case Expression::Kind::kTypeReference:
1305 case Expression::Kind::kCodeString:
Ethan Nicholas549c6b82021-06-25 12:31:44 -04001306 return true;
1307
Brian Osmanea485e52021-01-15 13:20:32 -05001308 default:
1309 SkDEBUGFAIL("Unexpected expression type");
1310 return true;
1311 }
1312 }
1313
1314private:
1315 const std::set<const Variable*>* fLoopIndices;
1316 using INHERITED = ProgramVisitor;
1317};
1318
1319class ES2IndexingVisitor : public ProgramVisitor {
1320public:
1321 ES2IndexingVisitor(ErrorReporter& errors) : fErrors(errors) {}
1322
1323 bool visitStatement(const Statement& s) override {
1324 if (s.is<ForStatement>()) {
1325 const ForStatement& f = s.as<ForStatement>();
1326 SkASSERT(f.initializer() && f.initializer()->is<VarDeclaration>());
1327 const Variable* var = &f.initializer()->as<VarDeclaration>().var();
1328 auto [iter, inserted] = fLoopIndices.insert(var);
1329 SkASSERT(inserted);
1330 bool result = this->visitStatement(*f.statement());
1331 fLoopIndices.erase(iter);
1332 return result;
1333 }
1334 return INHERITED::visitStatement(s);
1335 }
1336
1337 bool visitExpression(const Expression& e) override {
1338 if (e.is<IndexExpression>()) {
1339 const IndexExpression& i = e.as<IndexExpression>();
Brian Osman7b361492021-02-25 11:25:30 -05001340 ConstantExpressionVisitor indexerInvalid(&fLoopIndices);
Brian Osmanea485e52021-01-15 13:20:32 -05001341 if (indexerInvalid.visitExpression(*i.index())) {
Ethan Nicholas89cfde12021-09-27 11:20:34 -04001342 fErrors.error(i.fLine, "index expression must be constant");
Brian Osmanea485e52021-01-15 13:20:32 -05001343 return true;
1344 }
1345 }
1346 return INHERITED::visitExpression(e);
1347 }
1348
1349 using ProgramVisitor::visitProgramElement;
1350
1351private:
1352 ErrorReporter& fErrors;
1353 std::set<const Variable*> fLoopIndices;
1354 using INHERITED = ProgramVisitor;
1355};
1356
1357
1358void Analysis::ValidateIndexingForES2(const ProgramElement& pe, ErrorReporter& errors) {
1359 ES2IndexingVisitor visitor(errors);
1360 visitor.visitProgramElement(pe);
1361}
1362
Brian Osman7b361492021-02-25 11:25:30 -05001363bool Analysis::IsConstantExpression(const Expression& expr) {
1364 ConstantExpressionVisitor visitor(/*loopIndices=*/nullptr);
1365 return !visitor.visitExpression(expr);
1366}
1367
John Stiles958f4b52021-03-17 16:39:49 -04001368bool Analysis::CanExitWithoutReturningValue(const FunctionDeclaration& funcDecl,
1369 const Statement& body) {
1370 if (funcDecl.returnType().isVoid()) {
1371 return false;
1372 }
John Stilesb3dcbb12021-03-04 16:00:20 -05001373 ReturnsOnAllPathsVisitor visitor;
John Stiles958f4b52021-03-17 16:39:49 -04001374 visitor.visitStatement(body);
John Stilesb3dcbb12021-03-04 16:00:20 -05001375 return !visitor.fFoundReturn;
1376}
1377
John Stiles2ecc5952021-09-01 14:41:36 -04001378void Analysis::VerifyStaticTestsAndExpressions(const Program& program) {
1379 class TestsAndExpressions : public ProgramVisitor {
John Stiles0fc6bed2021-09-01 11:35:59 -04001380 public:
John Stiles2ecc5952021-09-01 14:41:36 -04001381 TestsAndExpressions(const Context& ctx) : fContext(ctx) {}
John Stiles0fc6bed2021-09-01 11:35:59 -04001382
1383 using ProgramVisitor::visitProgramElement;
1384
1385 bool visitStatement(const Statement& stmt) override {
John Stiles2ecc5952021-09-01 14:41:36 -04001386 if (!fContext.fConfig->fSettings.fPermitInvalidStaticTests) {
1387 switch (stmt.kind()) {
1388 case Statement::Kind::kIf:
1389 if (stmt.as<IfStatement>().isStatic()) {
Ethan Nicholas89cfde12021-09-27 11:20:34 -04001390 fContext.fErrors->error(stmt.fLine, "static if has non-static test");
John Stiles2ecc5952021-09-01 14:41:36 -04001391 }
1392 break;
John Stiles0fc6bed2021-09-01 11:35:59 -04001393
John Stiles2ecc5952021-09-01 14:41:36 -04001394 case Statement::Kind::kSwitch:
1395 if (stmt.as<SwitchStatement>().isStatic()) {
Ethan Nicholas89cfde12021-09-27 11:20:34 -04001396 fContext.fErrors->error(stmt.fLine,
John Stiles2ecc5952021-09-01 14:41:36 -04001397 "static switch has non-static test");
1398 }
1399 break;
John Stiles0fc6bed2021-09-01 11:35:59 -04001400
John Stiles2ecc5952021-09-01 14:41:36 -04001401 default:
1402 break;
1403 }
John Stiles0fc6bed2021-09-01 11:35:59 -04001404 }
1405 return INHERITED::visitStatement(stmt);
1406 }
1407
John Stiles2ecc5952021-09-01 14:41:36 -04001408 bool visitExpression(const Expression& expr) override {
1409 switch (expr.kind()) {
1410 case Expression::Kind::kFunctionCall: {
1411 const FunctionDeclaration& decl = expr.as<FunctionCall>().function();
1412 if (!decl.isBuiltin() && !decl.definition()) {
Ethan Nicholas89cfde12021-09-27 11:20:34 -04001413 fContext.fErrors->error(expr.fLine, "function '" + decl.description() +
1414 "' is not defined");
John Stiles2ecc5952021-09-01 14:41:36 -04001415 }
1416 break;
1417 }
1418 case Expression::Kind::kExternalFunctionReference:
1419 case Expression::Kind::kFunctionReference:
Brian Osman3099f792021-09-01 13:12:16 -04001420 case Expression::Kind::kMethodReference:
John Stiles2ecc5952021-09-01 14:41:36 -04001421 case Expression::Kind::kTypeReference:
1422 SkDEBUGFAIL("invalid reference-expr, should have been reported by coerce()");
Ethan Nicholas89cfde12021-09-27 11:20:34 -04001423 fContext.fErrors->error(expr.fLine, "invalid expression");
John Stiles2ecc5952021-09-01 14:41:36 -04001424 break;
1425 default:
1426 if (expr.type() == *fContext.fTypes.fInvalid) {
Ethan Nicholas89cfde12021-09-27 11:20:34 -04001427 fContext.fErrors->error(expr.fLine, "invalid expression");
John Stiles2ecc5952021-09-01 14:41:36 -04001428 }
1429 break;
1430 }
1431 return INHERITED::visitExpression(expr);
John Stiles0fc6bed2021-09-01 11:35:59 -04001432 }
1433
1434 private:
1435 using INHERITED = ProgramVisitor;
John Stiles2ecc5952021-09-01 14:41:36 -04001436 const Context& fContext;
John Stiles0fc6bed2021-09-01 11:35:59 -04001437 };
1438
John Stiles0fc6bed2021-09-01 11:35:59 -04001439 // Check all of the program's owned elements. (Built-in elements are assumed to be valid.)
John Stiles2ecc5952021-09-01 14:41:36 -04001440 TestsAndExpressions visitor{*program.fContext};
John Stiles0fc6bed2021-09-01 11:35:59 -04001441 for (const std::unique_ptr<ProgramElement>& element : program.ownedElements()) {
John Stiles2ecc5952021-09-01 14:41:36 -04001442 visitor.visitProgramElement(*element);
John Stiles0fc6bed2021-09-01 11:35:59 -04001443 }
1444}
1445
John Stiles49b1a422021-09-22 09:35:39 -04001446void Analysis::EliminateUnreachableCode(std::unique_ptr<Statement>& stmt, ProgramUsage* usage) {
1447 class UnreachableCodeEliminator : public ProgramWriter {
1448 public:
1449 UnreachableCodeEliminator(ProgramUsage* usage)
1450 : fUsage(usage) {
1451 fFoundFunctionExit.push(false);
1452 fFoundLoopExit.push(false);
1453 }
1454
1455 bool visitExpressionPtr(std::unique_ptr<Expression>& expr) override {
1456 // We don't need to look inside expressions at all.
1457 return false;
1458 }
1459
1460 bool visitStatementPtr(std::unique_ptr<Statement>& stmt) override {
1461 if (fFoundFunctionExit.top() || fFoundLoopExit.top()) {
1462 // If we already found an exit in this section, anything beyond it is dead code.
1463 if (!stmt->is<Nop>()) {
1464 // Eliminate the dead statement by substituting a Nop.
1465 if (fUsage) {
1466 fUsage->remove(stmt.get());
1467 }
1468 stmt = std::make_unique<Nop>();
1469 }
1470 return false;
1471 }
1472
1473 switch (stmt->kind()) {
1474 case Statement::Kind::kReturn:
1475 case Statement::Kind::kDiscard:
1476 // We found a function exit on this path.
1477 fFoundFunctionExit.top() = true;
1478 break;
1479
1480 case Statement::Kind::kBreak:
1481 case Statement::Kind::kContinue:
1482 // We found a loop exit on this path. Note that we skip over switch statements
1483 // completely when eliminating code, so any `break` statement would be breaking
1484 // out of a loop, not out of a switch.
1485 fFoundLoopExit.top() = true;
1486 break;
1487
1488 case Statement::Kind::kExpression:
1489 case Statement::Kind::kInlineMarker:
1490 case Statement::Kind::kNop:
1491 case Statement::Kind::kVarDeclaration:
1492 // These statements don't affect control flow.
1493 break;
1494
1495 case Statement::Kind::kBlock:
1496 // Blocks are on the straight-line path and don't affect control flow.
1497 return INHERITED::visitStatementPtr(stmt);
1498
1499 case Statement::Kind::kDo: {
1500 // Function-exits are allowed to propagate outside of a do-loop, because it
1501 // always executes its body at least once.
1502 fFoundLoopExit.push(false);
1503 bool result = INHERITED::visitStatementPtr(stmt);
1504 fFoundLoopExit.pop();
1505 return result;
1506 }
1507 case Statement::Kind::kFor: {
1508 // Function-exits are not allowed to propagate out, because a for-loop or while-
1509 // loop could potentially run zero times.
1510 fFoundFunctionExit.push(false);
1511 fFoundLoopExit.push(false);
1512 bool result = INHERITED::visitStatementPtr(stmt);
1513 fFoundLoopExit.pop();
1514 fFoundFunctionExit.pop();
1515 return result;
1516 }
1517 case Statement::Kind::kIf: {
1518 // This statement is conditional and encloses two inner sections of code.
1519 // If both sides contain a function-exit or loop-exit, that exit is allowed to
1520 // propagate out.
1521 IfStatement& ifStmt = stmt->as<IfStatement>();
1522
1523 fFoundFunctionExit.push(false);
1524 fFoundLoopExit.push(false);
1525 bool result = (ifStmt.ifTrue() && this->visitStatementPtr(ifStmt.ifTrue()));
1526 bool foundFunctionExitOnTrue = fFoundFunctionExit.top();
1527 bool foundLoopExitOnTrue = fFoundLoopExit.top();
1528 fFoundFunctionExit.pop();
1529 fFoundLoopExit.pop();
1530
1531 fFoundFunctionExit.push(false);
1532 fFoundLoopExit.push(false);
1533 result |= (ifStmt.ifFalse() && this->visitStatementPtr(ifStmt.ifFalse()));
1534 bool foundFunctionExitOnFalse = fFoundFunctionExit.top();
1535 bool foundLoopExitOnFalse = fFoundLoopExit.top();
1536 fFoundFunctionExit.pop();
1537 fFoundLoopExit.pop();
1538
1539 fFoundFunctionExit.top() |= foundFunctionExitOnTrue && foundFunctionExitOnFalse;
1540 fFoundLoopExit.top() |= foundLoopExitOnTrue && foundLoopExitOnFalse;
1541 return result;
1542 }
1543 case Statement::Kind::kSwitch:
1544 case Statement::Kind::kSwitchCase:
1545 // We skip past switch statements entirely when scanning for dead code. Their
1546 // control flow is quite complex and we already do a good job of flattening out
1547 // switches on constant values.
1548 break;
1549 }
1550
1551 return false;
1552 }
1553
1554 ProgramUsage* fUsage;
1555 std::stack<bool> fFoundFunctionExit;
1556 std::stack<bool> fFoundLoopExit;
1557
1558 using INHERITED = ProgramWriter;
1559 };
1560
1561 UnreachableCodeEliminator visitor{usage};
1562 visitor.visitStatementPtr(stmt);
1563}
1564
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001565////////////////////////////////////////////////////////////////////////////////
1566// ProgramVisitor
1567
Brian Osman133724c2020-10-28 14:14:39 -04001568bool ProgramVisitor::visit(const Program& program) {
1569 for (const ProgramElement* pe : program.elements()) {
Brian Osman1179fcf2020-10-08 16:04:40 -04001570 if (this->visitProgramElement(*pe)) {
John Stiles933abe32020-08-28 11:58:40 -04001571 return true;
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001572 }
1573 }
John Stiles933abe32020-08-28 11:58:40 -04001574 return false;
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001575}
1576
John Stiles48b25582021-03-11 14:26:42 -05001577template <typename T> bool TProgramVisitor<T>::visitExpression(typename T::Expression& e) {
John Stiles70b82422020-09-30 10:55:12 -04001578 switch (e.kind()) {
Brian Osmanbe0b3b72021-01-06 14:27:35 -05001579 case Expression::Kind::kExternalFunctionReference:
Ethan Nicholase6592142020-09-08 10:22:09 -04001580 case Expression::Kind::kFunctionReference:
John Stiles7591d4b2021-09-13 13:32:06 -04001581 case Expression::Kind::kLiteral:
Brian Osman3099f792021-09-01 13:12:16 -04001582 case Expression::Kind::kMethodReference:
Ethan Nicholas549c6b82021-06-25 12:31:44 -04001583 case Expression::Kind::kPoison:
Ethan Nicholase6592142020-09-08 10:22:09 -04001584 case Expression::Kind::kSetting:
1585 case Expression::Kind::kTypeReference:
1586 case Expression::Kind::kVariableReference:
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001587 // Leaf expressions return false
1588 return false;
John Stiles70b82422020-09-30 10:55:12 -04001589
Ethan Nicholase6592142020-09-08 10:22:09 -04001590 case Expression::Kind::kBinary: {
John Stiles70b82422020-09-30 10:55:12 -04001591 auto& b = e.template as<BinaryExpression>();
John Stiles48b25582021-03-11 14:26:42 -05001592 return (b.left() && this->visitExpressionPtr(b.left())) ||
1593 (b.right() && this->visitExpressionPtr(b.right()));
John Stiles70b82422020-09-30 10:55:12 -04001594 }
Brian Osmaneb0f29d2021-08-04 11:34:16 -04001595 case Expression::Kind::kChildCall: {
1596 // We don't visit the child variable itself, just the arguments
1597 auto& c = e.template as<ChildCall>();
1598 for (auto& arg : c.arguments()) {
1599 if (arg && this->visitExpressionPtr(arg)) { return true; }
1600 }
1601 return false;
1602 }
John Stiles7384b372021-04-01 13:48:15 -04001603 case Expression::Kind::kConstructorArray:
John Stilese3ae9682021-08-05 10:35:01 -04001604 case Expression::Kind::kConstructorArrayCast:
John Stiles8cad6372021-04-07 12:31:13 -04001605 case Expression::Kind::kConstructorCompound:
1606 case Expression::Kind::kConstructorCompoundCast:
John Stiles2938eea2021-04-01 18:58:25 -04001607 case Expression::Kind::kConstructorDiagonalMatrix:
John Stiles5abb9e12021-04-06 13:47:19 -04001608 case Expression::Kind::kConstructorMatrixResize:
John Stilesfd7252f2021-04-04 22:24:40 -04001609 case Expression::Kind::kConstructorScalarCast:
John Stilesd47330f2021-04-08 23:25:52 -04001610 case Expression::Kind::kConstructorSplat:
1611 case Expression::Kind::kConstructorStruct: {
John Stiles7384b372021-04-01 13:48:15 -04001612 auto& c = e.asAnyConstructor();
1613 for (auto& arg : c.argumentSpan()) {
John Stiles48b25582021-03-11 14:26:42 -05001614 if (this->visitExpressionPtr(arg)) { return true; }
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001615 }
John Stiles70b82422020-09-30 10:55:12 -04001616 return false;
1617 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001618 case Expression::Kind::kExternalFunctionCall: {
John Stiles70b82422020-09-30 10:55:12 -04001619 auto& c = e.template as<ExternalFunctionCall>();
Ethan Nicholas6e86ec92020-09-30 14:29:56 -04001620 for (auto& arg : c.arguments()) {
John Stiles48b25582021-03-11 14:26:42 -05001621 if (this->visitExpressionPtr(arg)) { return true; }
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001622 }
John Stiles70b82422020-09-30 10:55:12 -04001623 return false;
1624 }
John Stilesd7ab4502020-09-24 22:41:00 -04001625 case Expression::Kind::kFieldAccess:
John Stiles48b25582021-03-11 14:26:42 -05001626 return this->visitExpressionPtr(e.template as<FieldAccess>().base());
John Stiles70b82422020-09-30 10:55:12 -04001627
Ethan Nicholase6592142020-09-08 10:22:09 -04001628 case Expression::Kind::kFunctionCall: {
John Stiles70b82422020-09-30 10:55:12 -04001629 auto& c = e.template as<FunctionCall>();
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001630 for (auto& arg : c.arguments()) {
John Stiles48b25582021-03-11 14:26:42 -05001631 if (arg && this->visitExpressionPtr(arg)) { return true; }
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001632 }
John Stiles70b82422020-09-30 10:55:12 -04001633 return false;
1634 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001635 case Expression::Kind::kIndex: {
John Stiles70b82422020-09-30 10:55:12 -04001636 auto& i = e.template as<IndexExpression>();
John Stiles48b25582021-03-11 14:26:42 -05001637 return this->visitExpressionPtr(i.base()) || this->visitExpressionPtr(i.index());
John Stiles70b82422020-09-30 10:55:12 -04001638 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001639 case Expression::Kind::kPostfix:
John Stiles48b25582021-03-11 14:26:42 -05001640 return this->visitExpressionPtr(e.template as<PostfixExpression>().operand());
John Stiles70b82422020-09-30 10:55:12 -04001641
Ethan Nicholase6592142020-09-08 10:22:09 -04001642 case Expression::Kind::kPrefix:
John Stiles48b25582021-03-11 14:26:42 -05001643 return this->visitExpressionPtr(e.template as<PrefixExpression>().operand());
John Stiles70b82422020-09-30 10:55:12 -04001644
Brian Osman010ce6a2020-10-19 16:34:10 -04001645 case Expression::Kind::kSwizzle: {
1646 auto& s = e.template as<Swizzle>();
John Stiles48b25582021-03-11 14:26:42 -05001647 return s.base() && this->visitExpressionPtr(s.base());
Brian Osman010ce6a2020-10-19 16:34:10 -04001648 }
John Stiles70b82422020-09-30 10:55:12 -04001649
Ethan Nicholase6592142020-09-08 10:22:09 -04001650 case Expression::Kind::kTernary: {
John Stiles70b82422020-09-30 10:55:12 -04001651 auto& t = e.template as<TernaryExpression>();
John Stiles48b25582021-03-11 14:26:42 -05001652 return this->visitExpressionPtr(t.test()) ||
1653 (t.ifTrue() && this->visitExpressionPtr(t.ifTrue())) ||
1654 (t.ifFalse() && this->visitExpressionPtr(t.ifFalse()));
John Stiles70b82422020-09-30 10:55:12 -04001655 }
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001656 default:
1657 SkUNREACHABLE;
1658 }
1659}
1660
John Stiles48b25582021-03-11 14:26:42 -05001661template <typename T> bool TProgramVisitor<T>::visitStatement(typename T::Statement& s) {
John Stiles70b82422020-09-30 10:55:12 -04001662 switch (s.kind()) {
Ethan Nicholase6592142020-09-08 10:22:09 -04001663 case Statement::Kind::kBreak:
1664 case Statement::Kind::kContinue:
1665 case Statement::Kind::kDiscard:
John Stiles98c1f822020-09-09 14:18:53 -04001666 case Statement::Kind::kInlineMarker:
Ethan Nicholase6592142020-09-08 10:22:09 -04001667 case Statement::Kind::kNop:
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001668 // Leaf statements just return false
1669 return false;
John Stiles70b82422020-09-30 10:55:12 -04001670
Ethan Nicholase6592142020-09-08 10:22:09 -04001671 case Statement::Kind::kBlock:
John Stiles70b82422020-09-30 10:55:12 -04001672 for (auto& stmt : s.template as<Block>().children()) {
John Stiles48b25582021-03-11 14:26:42 -05001673 if (stmt && this->visitStatementPtr(stmt)) {
Ethan Nicholas7bd60432020-09-25 14:31:59 -04001674 return true;
1675 }
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001676 }
1677 return false;
John Stiles70b82422020-09-30 10:55:12 -04001678
John Stilesa0e56e32021-03-03 13:14:37 -05001679 case Statement::Kind::kSwitchCase: {
1680 auto& sc = s.template as<SwitchCase>();
John Stiles48b25582021-03-11 14:26:42 -05001681 if (sc.value() && this->visitExpressionPtr(sc.value())) {
John Stilesa0e56e32021-03-03 13:14:37 -05001682 return true;
1683 }
John Stiles48b25582021-03-11 14:26:42 -05001684 return this->visitStatementPtr(sc.statement());
John Stilesa0e56e32021-03-03 13:14:37 -05001685 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001686 case Statement::Kind::kDo: {
John Stiles70b82422020-09-30 10:55:12 -04001687 auto& d = s.template as<DoStatement>();
John Stiles48b25582021-03-11 14:26:42 -05001688 return this->visitExpressionPtr(d.test()) || this->visitStatementPtr(d.statement());
John Stiles70b82422020-09-30 10:55:12 -04001689 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001690 case Statement::Kind::kExpression:
John Stiles48b25582021-03-11 14:26:42 -05001691 return this->visitExpressionPtr(s.template as<ExpressionStatement>().expression());
John Stiles70b82422020-09-30 10:55:12 -04001692
Ethan Nicholase6592142020-09-08 10:22:09 -04001693 case Statement::Kind::kFor: {
John Stiles70b82422020-09-30 10:55:12 -04001694 auto& f = s.template as<ForStatement>();
John Stiles48b25582021-03-11 14:26:42 -05001695 return (f.initializer() && this->visitStatementPtr(f.initializer())) ||
1696 (f.test() && this->visitExpressionPtr(f.test())) ||
1697 (f.next() && this->visitExpressionPtr(f.next())) ||
1698 this->visitStatementPtr(f.statement());
John Stiles70b82422020-09-30 10:55:12 -04001699 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001700 case Statement::Kind::kIf: {
John Stiles70b82422020-09-30 10:55:12 -04001701 auto& i = s.template as<IfStatement>();
John Stiles48b25582021-03-11 14:26:42 -05001702 return (i.test() && this->visitExpressionPtr(i.test())) ||
1703 (i.ifTrue() && this->visitStatementPtr(i.ifTrue())) ||
1704 (i.ifFalse() && this->visitStatementPtr(i.ifFalse()));
John Stiles70b82422020-09-30 10:55:12 -04001705 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001706 case Statement::Kind::kReturn: {
John Stiles70b82422020-09-30 10:55:12 -04001707 auto& r = s.template as<ReturnStatement>();
John Stiles48b25582021-03-11 14:26:42 -05001708 return r.expression() && this->visitExpressionPtr(r.expression());
John Stiles70b82422020-09-30 10:55:12 -04001709 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001710 case Statement::Kind::kSwitch: {
John Stiles70b82422020-09-30 10:55:12 -04001711 auto& sw = s.template as<SwitchStatement>();
John Stiles48b25582021-03-11 14:26:42 -05001712 if (this->visitExpressionPtr(sw.value())) {
John Stiles70b82422020-09-30 10:55:12 -04001713 return true;
1714 }
John Stiles48b25582021-03-11 14:26:42 -05001715 for (auto& c : sw.cases()) {
1716 if (this->visitStatementPtr(c)) {
John Stiles70b82422020-09-30 10:55:12 -04001717 return true;
1718 }
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001719 }
John Stiles70b82422020-09-30 10:55:12 -04001720 return false;
1721 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001722 case Statement::Kind::kVarDeclaration: {
John Stiles70b82422020-09-30 10:55:12 -04001723 auto& v = s.template as<VarDeclaration>();
John Stiles48b25582021-03-11 14:26:42 -05001724 return v.value() && this->visitExpressionPtr(v.value());
John Stiles70b82422020-09-30 10:55:12 -04001725 }
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001726 default:
1727 SkUNREACHABLE;
1728 }
1729}
1730
John Stiles48b25582021-03-11 14:26:42 -05001731template <typename T> bool TProgramVisitor<T>::visitProgramElement(typename T::ProgramElement& pe) {
John Stiles70b82422020-09-30 10:55:12 -04001732 switch (pe.kind()) {
Ethan Nicholase6592142020-09-08 10:22:09 -04001733 case ProgramElement::Kind::kExtension:
John Stiles569249b2020-11-03 12:18:22 -05001734 case ProgramElement::Kind::kFunctionPrototype:
John Stilesd39aec02020-12-03 10:42:26 -05001735 case ProgramElement::Kind::kInterfaceBlock:
Ethan Nicholase6592142020-09-08 10:22:09 -04001736 case ProgramElement::Kind::kModifiers:
John Stilesdc75a972020-11-25 16:24:55 -05001737 case ProgramElement::Kind::kStructDefinition:
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001738 // Leaf program elements just return false by default
1739 return false;
John Stiles70b82422020-09-30 10:55:12 -04001740
Ethan Nicholase6592142020-09-08 10:22:09 -04001741 case ProgramElement::Kind::kFunction:
John Stiles48b25582021-03-11 14:26:42 -05001742 return this->visitStatementPtr(pe.template as<FunctionDefinition>().body());
John Stiles70b82422020-09-30 10:55:12 -04001743
Brian Osmanc0213602020-10-06 14:43:32 -04001744 case ProgramElement::Kind::kGlobalVar:
John Stiles48b25582021-03-11 14:26:42 -05001745 return this->visitStatementPtr(pe.template as<GlobalVarDeclaration>().declaration());
John Stiles70b82422020-09-30 10:55:12 -04001746
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001747 default:
1748 SkUNREACHABLE;
1749 }
1750}
1751
John Stiles48b25582021-03-11 14:26:42 -05001752template class TProgramVisitor<ProgramVisitorTypes>;
1753template class TProgramVisitor<ProgramWriterTypes>;
John Stiles70b82422020-09-30 10:55:12 -04001754
John Stilesa6841be2020-08-06 14:11:56 -04001755} // namespace SkSL