blob: 175131580f6a97471d139453649a446fa821928b [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"
Ethan Nicholas17807552021-10-01 09:42:36 -040019#include "src/sksl/analysis/SkSLProgramVisitor.h"
Michael Ludwig8f3a8362020-06-29 17:27:00 -040020#include "src/sksl/ir/SkSLExpression.h"
21#include "src/sksl/ir/SkSLProgram.h"
Ethan Nicholas17807552021-10-01 09:42:36 -040022#include "src/sksl/transform/SkSLProgramWriter.h"
Michael Ludwig8f3a8362020-06-29 17:27:00 -040023
24// ProgramElements
Michael Ludwig8f3a8362020-06-29 17:27:00 -040025#include "src/sksl/ir/SkSLExtension.h"
26#include "src/sksl/ir/SkSLFunctionDefinition.h"
27#include "src/sksl/ir/SkSLInterfaceBlock.h"
Michael Ludwig8f3a8362020-06-29 17:27:00 -040028#include "src/sksl/ir/SkSLVarDeclarations.h"
29
30// Statements
31#include "src/sksl/ir/SkSLBlock.h"
32#include "src/sksl/ir/SkSLBreakStatement.h"
33#include "src/sksl/ir/SkSLContinueStatement.h"
34#include "src/sksl/ir/SkSLDiscardStatement.h"
35#include "src/sksl/ir/SkSLDoStatement.h"
36#include "src/sksl/ir/SkSLExpressionStatement.h"
37#include "src/sksl/ir/SkSLForStatement.h"
38#include "src/sksl/ir/SkSLIfStatement.h"
39#include "src/sksl/ir/SkSLNop.h"
40#include "src/sksl/ir/SkSLReturnStatement.h"
41#include "src/sksl/ir/SkSLSwitchStatement.h"
Michael Ludwig8f3a8362020-06-29 17:27:00 -040042
43// Expressions
44#include "src/sksl/ir/SkSLBinaryExpression.h"
Brian Osmaneb0f29d2021-08-04 11:34:16 -040045#include "src/sksl/ir/SkSLChildCall.h"
Michael Ludwig8f3a8362020-06-29 17:27:00 -040046#include "src/sksl/ir/SkSLConstructor.h"
John Stilese1182782021-03-30 22:09:37 -040047#include "src/sksl/ir/SkSLConstructorDiagonalMatrix.h"
John Stiles5abb9e12021-04-06 13:47:19 -040048#include "src/sksl/ir/SkSLConstructorMatrixResize.h"
Michael Ludwig8f3a8362020-06-29 17:27:00 -040049#include "src/sksl/ir/SkSLExternalFunctionCall.h"
Brian Osmanbe0b3b72021-01-06 14:27:35 -050050#include "src/sksl/ir/SkSLExternalFunctionReference.h"
Michael Ludwig8f3a8362020-06-29 17:27:00 -040051#include "src/sksl/ir/SkSLFieldAccess.h"
Michael Ludwig8f3a8362020-06-29 17:27:00 -040052#include "src/sksl/ir/SkSLFunctionCall.h"
53#include "src/sksl/ir/SkSLFunctionReference.h"
54#include "src/sksl/ir/SkSLIndexExpression.h"
John Stiles98c1f822020-09-09 14:18:53 -040055#include "src/sksl/ir/SkSLInlineMarker.h"
John Stiles7591d4b2021-09-13 13:32:06 -040056#include "src/sksl/ir/SkSLLiteral.h"
Michael Ludwig8f3a8362020-06-29 17:27:00 -040057#include "src/sksl/ir/SkSLPostfixExpression.h"
58#include "src/sksl/ir/SkSLPrefixExpression.h"
59#include "src/sksl/ir/SkSLSetting.h"
60#include "src/sksl/ir/SkSLSwizzle.h"
61#include "src/sksl/ir/SkSLTernaryExpression.h"
62#include "src/sksl/ir/SkSLTypeReference.h"
63#include "src/sksl/ir/SkSLVariableReference.h"
64
John Stiles49b1a422021-09-22 09:35:39 -040065#include <stack>
66
Michael Ludwig8f3a8362020-06-29 17:27:00 -040067namespace SkSL {
68
69namespace {
70
Brian Osmaneb0f29d2021-08-04 11:34:16 -040071// Visitor that determines the merged SampleUsage for a given child in the program.
Brian Osman1298bc42020-06-30 13:39:35 -040072class MergeSampleUsageVisitor : public ProgramVisitor {
Michael Ludwig8f3a8362020-06-29 17:27:00 -040073public:
Brian Osmaneb0f29d2021-08-04 11:34:16 -040074 MergeSampleUsageVisitor(const Context& context,
75 const Variable& child,
76 bool writesToSampleCoords)
77 : fContext(context), fChild(child), fWritesToSampleCoords(writesToSampleCoords) {}
Michael Ludwig8f3a8362020-06-29 17:27:00 -040078
Brian Osman1298bc42020-06-30 13:39:35 -040079 SampleUsage visit(const Program& program) {
80 fUsage = SampleUsage(); // reset to none
John Stilesd7ab4502020-09-24 22:41:00 -040081 INHERITED::visit(program);
Brian Osman1298bc42020-06-30 13:39:35 -040082 return fUsage;
Michael Ludwig8f3a8362020-06-29 17:27:00 -040083 }
84
Brian Osman8cdf28f2021-05-24 09:52:39 -040085 int elidedSampleCoordCount() const { return fElidedSampleCoordCount; }
86
Michael Ludwig8f3a8362020-06-29 17:27:00 -040087protected:
John Stiles933abe32020-08-28 11:58:40 -040088 const Context& fContext;
Brian Osmaneb0f29d2021-08-04 11:34:16 -040089 const Variable& fChild;
Brian Osman4d571112021-04-27 09:10:10 -040090 const bool fWritesToSampleCoords;
Brian Osman1298bc42020-06-30 13:39:35 -040091 SampleUsage fUsage;
Brian Osman8cdf28f2021-05-24 09:52:39 -040092 int fElidedSampleCoordCount = 0;
Michael Ludwig8f3a8362020-06-29 17:27:00 -040093
94 bool visitExpression(const Expression& e) override {
Brian Osmaneb0f29d2021-08-04 11:34:16 -040095 // Looking for child(...)
96 if (e.is<ChildCall>() && &e.as<ChildCall>().child() == &fChild) {
97 // Determine the type of call at this site, and merge it with the accumulated state
98 const ExpressionArray& arguments = e.as<ChildCall>().arguments();
99 SkASSERT(arguments.size() >= 1);
100
101 const Expression* maybeCoords = arguments[0].get();
102 if (maybeCoords->type() == *fContext.fTypes.fFloat2) {
103 // If the coords are a direct reference to the program's sample-coords, and those
104 // coords are never modified, we can conservatively turn this into PassThrough
105 // sampling. In all other cases, we consider it Explicit.
106 if (!fWritesToSampleCoords && maybeCoords->is<VariableReference>() &&
107 maybeCoords->as<VariableReference>().variable()->modifiers().fLayout.fBuiltin ==
108 SK_MAIN_COORDS_BUILTIN) {
Brian Osman1298bc42020-06-30 13:39:35 -0400109 fUsage.merge(SampleUsage::PassThrough());
Brian Osmaneb0f29d2021-08-04 11:34:16 -0400110 ++fElidedSampleCoordCount;
111 } else {
112 fUsage.merge(SampleUsage::Explicit());
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400113 }
Brian Osmaneb0f29d2021-08-04 11:34:16 -0400114 } else {
115 // child(inputColor) or child(srcColor, dstColor) -> PassThrough
116 fUsage.merge(SampleUsage::PassThrough());
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400117 }
118 }
119
John Stilesd7ab4502020-09-24 22:41:00 -0400120 return INHERITED::visitExpression(e);
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400121 }
122
John Stiles7571f9e2020-09-02 22:42:33 -0400123 using INHERITED = ProgramVisitor;
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400124};
125
Brian Osman92aac1e2020-08-05 16:48:58 -0400126// Visitor that searches through the program for references to a particular builtin variable
127class BuiltinVariableVisitor : public ProgramVisitor {
128public:
129 BuiltinVariableVisitor(int builtin) : fBuiltin(builtin) {}
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400130
131 bool visitExpression(const Expression& e) override {
Brian Osman79457ef2020-09-24 15:01:27 -0400132 if (e.is<VariableReference>()) {
John Stiles403a3632020-08-20 12:11:48 -0400133 const VariableReference& var = e.as<VariableReference>();
Ethan Nicholas78686922020-10-08 06:46:27 -0400134 return var.variable()->modifiers().fLayout.fBuiltin == fBuiltin;
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400135 }
John Stilesd7ab4502020-09-24 22:41:00 -0400136 return INHERITED::visitExpression(e);
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400137 }
138
Brian Osman92aac1e2020-08-05 16:48:58 -0400139 int fBuiltin;
140
John Stiles7571f9e2020-09-02 22:42:33 -0400141 using INHERITED = ProgramVisitor;
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400142};
143
Brian Osmaneb0f29d2021-08-04 11:34:16 -0400144// Visitor that searches for child calls from a function other than main()
Brian Osman04d79fc2021-07-02 13:25:35 -0400145class SampleOutsideMainVisitor : public ProgramVisitor {
146public:
147 SampleOutsideMainVisitor() {}
148
149 bool visitExpression(const Expression& e) override {
Brian Osmaneb0f29d2021-08-04 11:34:16 -0400150 if (e.is<ChildCall>()) {
151 return true;
Brian Osman04d79fc2021-07-02 13:25:35 -0400152 }
153 return INHERITED::visitExpression(e);
154 }
155
156 bool visitProgramElement(const ProgramElement& p) override {
157 return p.is<FunctionDefinition>() &&
158 !p.as<FunctionDefinition>().declaration().isMain() &&
159 INHERITED::visitProgramElement(p);
160 }
161
162 using INHERITED = ProgramVisitor;
163};
164
Ethan Nicholas6e0fa402020-08-20 14:08:23 -0400165// Visitor that counts the number of nodes visited
166class NodeCountVisitor : public ProgramVisitor {
167public:
John Stiles2c1e4922020-10-01 09:14:14 -0400168 NodeCountVisitor(int limit) : fLimit(limit) {}
169
Ethan Nicholas6e0fa402020-08-20 14:08:23 -0400170 int visit(const Statement& s) {
Ethan Nicholas6e0fa402020-08-20 14:08:23 -0400171 this->visitStatement(s);
172 return fCount;
173 }
174
175 bool visitExpression(const Expression& e) override {
176 ++fCount;
John Stiles9b9415e2020-11-23 14:48:06 -0500177 return (fCount >= fLimit) || INHERITED::visitExpression(e);
Ethan Nicholas6e0fa402020-08-20 14:08:23 -0400178 }
179
180 bool visitProgramElement(const ProgramElement& p) override {
181 ++fCount;
John Stiles9b9415e2020-11-23 14:48:06 -0500182 return (fCount >= fLimit) || INHERITED::visitProgramElement(p);
Ethan Nicholas6e0fa402020-08-20 14:08:23 -0400183 }
184
185 bool visitStatement(const Statement& s) override {
186 ++fCount;
John Stiles9b9415e2020-11-23 14:48:06 -0500187 return (fCount >= fLimit) || INHERITED::visitStatement(s);
Ethan Nicholas6e0fa402020-08-20 14:08:23 -0400188 }
189
190private:
John Stiles2c1e4922020-10-01 09:14:14 -0400191 int fCount = 0;
192 int fLimit;
Ethan Nicholas6e0fa402020-08-20 14:08:23 -0400193
John Stiles7571f9e2020-09-02 22:42:33 -0400194 using INHERITED = ProgramVisitor;
Ethan Nicholas6e0fa402020-08-20 14:08:23 -0400195};
196
Brian Osman010ce6a2020-10-19 16:34:10 -0400197class ProgramUsageVisitor : public ProgramVisitor {
Brian Osman2e25ff42020-10-15 10:32:04 -0400198public:
Brian Osman010ce6a2020-10-19 16:34:10 -0400199 ProgramUsageVisitor(ProgramUsage* usage, int delta) : fUsage(usage), fDelta(delta) {}
200
John Stiles39465b82021-03-18 09:19:55 -0400201 bool visitProgramElement(const ProgramElement& pe) override {
202 if (pe.is<FunctionDefinition>()) {
203 for (const Variable* param : pe.as<FunctionDefinition>().declaration().parameters()) {
204 // Ensure function-parameter variables exist in the variable usage map. They aren't
205 // otherwise declared, but ProgramUsage::get() should be able to find them, even if
206 // they are unread and unwritten.
207 fUsage->fVariableCounts[param];
208 }
John Stiles8e2a84b2021-04-19 09:35:38 -0400209 } else if (pe.is<InterfaceBlock>()) {
210 // Ensure interface-block variables exist in the variable usage map.
211 fUsage->fVariableCounts[&pe.as<InterfaceBlock>().variable()];
John Stiles39465b82021-03-18 09:19:55 -0400212 }
213 return INHERITED::visitProgramElement(pe);
214 }
215
John Stiles04a8a542021-03-10 19:03:26 -0500216 bool visitStatement(const Statement& s) override {
217 if (s.is<VarDeclaration>()) {
218 // Add all declared variables to the usage map (even if never otherwise accessed).
219 const VarDeclaration& vd = s.as<VarDeclaration>();
220 ProgramUsage::VariableCounts& counts = fUsage->fVariableCounts[&vd.var()];
221 counts.fDeclared += fDelta;
222 SkASSERT(counts.fDeclared >= 0);
223 if (vd.value()) {
224 // The initial-value expression, when present, counts as a write.
225 counts.fWrite += fDelta;
226 }
227 }
228 return INHERITED::visitStatement(s);
229 }
230
Brian Osman2e25ff42020-10-15 10:32:04 -0400231 bool visitExpression(const Expression& e) override {
232 if (e.is<FunctionCall>()) {
233 const FunctionDeclaration* f = &e.as<FunctionCall>().function();
Brian Osman010ce6a2020-10-19 16:34:10 -0400234 fUsage->fCallCounts[f] += fDelta;
235 SkASSERT(fUsage->fCallCounts[f] >= 0);
236 } else if (e.is<VariableReference>()) {
237 const VariableReference& ref = e.as<VariableReference>();
238 ProgramUsage::VariableCounts& counts = fUsage->fVariableCounts[ref.variable()];
239 switch (ref.refKind()) {
240 case VariableRefKind::kRead:
241 counts.fRead += fDelta;
242 break;
243 case VariableRefKind::kWrite:
244 counts.fWrite += fDelta;
245 break;
246 case VariableRefKind::kReadWrite:
247 case VariableRefKind::kPointer:
248 counts.fRead += fDelta;
249 counts.fWrite += fDelta;
250 break;
251 }
252 SkASSERT(counts.fRead >= 0 && counts.fWrite >= 0);
Brian Osman2e25ff42020-10-15 10:32:04 -0400253 }
254 return INHERITED::visitExpression(e);
255 }
256
Brian Osman010ce6a2020-10-19 16:34:10 -0400257 using ProgramVisitor::visitProgramElement;
258 using ProgramVisitor::visitStatement;
259
260 ProgramUsage* fUsage;
261 int fDelta;
Brian Osman2e25ff42020-10-15 10:32:04 -0400262 using INHERITED = ProgramVisitor;
263};
264
Ethan Nicholas765d2fe2020-08-26 08:29:55 -0400265class VariableWriteVisitor : public ProgramVisitor {
266public:
267 VariableWriteVisitor(const Variable* var)
268 : fVar(var) {}
269
270 bool visit(const Statement& s) {
271 return this->visitStatement(s);
272 }
273
274 bool visitExpression(const Expression& e) override {
Brian Osman79457ef2020-09-24 15:01:27 -0400275 if (e.is<VariableReference>()) {
Ethan Nicholas765d2fe2020-08-26 08:29:55 -0400276 const VariableReference& ref = e.as<VariableReference>();
Ethan Nicholas453f67f2020-10-09 10:43:45 -0400277 if (ref.variable() == fVar &&
278 (ref.refKind() == VariableReference::RefKind::kWrite ||
279 ref.refKind() == VariableReference::RefKind::kReadWrite ||
280 ref.refKind() == VariableReference::RefKind::kPointer)) {
Ethan Nicholas765d2fe2020-08-26 08:29:55 -0400281 return true;
282 }
283 }
John Stilesd7ab4502020-09-24 22:41:00 -0400284 return INHERITED::visitExpression(e);
Ethan Nicholas765d2fe2020-08-26 08:29:55 -0400285 }
286
287private:
288 const Variable* fVar;
289
John Stiles7571f9e2020-09-02 22:42:33 -0400290 using INHERITED = ProgramVisitor;
Ethan Nicholas765d2fe2020-08-26 08:29:55 -0400291};
292
John Stilesa976da72020-09-25 23:06:26 -0400293// If a caller doesn't care about errors, we can use this trivial reporter that just counts up.
294class TrivialErrorReporter : public ErrorReporter {
295public:
John Stilesbb8cf582021-08-26 23:34:59 -0400296 ~TrivialErrorReporter() override { this->reportPendingErrors({}); }
Ethan Nicholas32724122021-09-07 13:49:07 -0400297 void handleError(skstd::string_view, PositionInfo) override {}
John Stilesa976da72020-09-25 23:06:26 -0400298};
299
John Stilesdce4d3e2020-09-25 14:35:13 -0400300// This isn't actually using ProgramVisitor, because it only considers a subset of the fields for
301// any given expression kind. For instance, when indexing an array (e.g. `x[1]`), we only want to
302// know if the base (`x`) is assignable; the index expression (`1`) doesn't need to be.
303class IsAssignableVisitor {
304public:
John Stilesb21fac22020-12-04 15:36:49 -0500305 IsAssignableVisitor(ErrorReporter* errors) : fErrors(errors) {}
John Stilesdce4d3e2020-09-25 14:35:13 -0400306
John Stilesb21fac22020-12-04 15:36:49 -0500307 bool visit(Expression& expr, Analysis::AssignmentInfo* info) {
Ethan Nicholas67a0a8a2021-01-13 12:36:02 -0500308 int oldErrorCount = fErrors->errorCount();
John Stilesdce4d3e2020-09-25 14:35:13 -0400309 this->visitExpression(expr);
John Stilesb21fac22020-12-04 15:36:49 -0500310 if (info) {
311 info->fAssignedVar = fAssignedVar;
John Stilesb21fac22020-12-04 15:36:49 -0500312 }
Ethan Nicholas67a0a8a2021-01-13 12:36:02 -0500313 return fErrors->errorCount() == oldErrorCount;
John Stilesdce4d3e2020-09-25 14:35:13 -0400314 }
315
316 void visitExpression(Expression& expr) {
317 switch (expr.kind()) {
318 case Expression::Kind::kVariableReference: {
319 VariableReference& varRef = expr.as<VariableReference>();
Ethan Nicholas78686922020-10-08 06:46:27 -0400320 const Variable* var = varRef.variable();
Brian Osmane49703f2021-04-19 11:15:24 -0400321 if (var->modifiers().fFlags & (Modifiers::kConst_Flag | Modifiers::kUniform_Flag)) {
Ethan Nicholas89cfde12021-09-27 11:20:34 -0400322 fErrors->error(expr.fLine,
Ethan Nicholase2c49992020-10-05 11:49:11 -0400323 "cannot modify immutable variable '" + var->name() + "'");
John Stilesb21fac22020-12-04 15:36:49 -0500324 } else {
325 SkASSERT(fAssignedVar == nullptr);
326 fAssignedVar = &varRef;
John Stilesdce4d3e2020-09-25 14:35:13 -0400327 }
328 break;
329 }
330 case Expression::Kind::kFieldAccess:
Ethan Nicholas7a95b202020-10-09 11:55:40 -0400331 this->visitExpression(*expr.as<FieldAccess>().base());
John Stilesdce4d3e2020-09-25 14:35:13 -0400332 break;
333
334 case Expression::Kind::kSwizzle: {
335 const Swizzle& swizzle = expr.as<Swizzle>();
336 this->checkSwizzleWrite(swizzle);
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400337 this->visitExpression(*swizzle.base());
John Stilesdce4d3e2020-09-25 14:35:13 -0400338 break;
339 }
John Stiles47c0a742021-02-09 09:30:35 -0500340 case Expression::Kind::kIndex:
341 this->visitExpression(*expr.as<IndexExpression>().base());
John Stilesdce4d3e2020-09-25 14:35:13 -0400342 break;
John Stiles47c0a742021-02-09 09:30:35 -0500343
Ethan Nicholasc898d042021-08-28 19:53:34 -0400344 case Expression::Kind::kPoison:
345 break;
346
John Stilesdce4d3e2020-09-25 14:35:13 -0400347 default:
Ethan Nicholas89cfde12021-09-27 11:20:34 -0400348 fErrors->error(expr.fLine, "cannot assign to this expression");
John Stilesdce4d3e2020-09-25 14:35:13 -0400349 break;
350 }
351 }
352
353private:
354 void checkSwizzleWrite(const Swizzle& swizzle) {
355 int bits = 0;
John Stiles6e88e042021-02-19 14:09:38 -0500356 for (int8_t idx : swizzle.components()) {
357 SkASSERT(idx >= SwizzleComponent::X && idx <= SwizzleComponent::W);
John Stilesdce4d3e2020-09-25 14:35:13 -0400358 int bit = 1 << idx;
359 if (bits & bit) {
Ethan Nicholas89cfde12021-09-27 11:20:34 -0400360 fErrors->error(swizzle.fLine,
John Stilesa976da72020-09-25 23:06:26 -0400361 "cannot write to the same swizzle field more than once");
John Stilesdce4d3e2020-09-25 14:35:13 -0400362 break;
363 }
364 bits |= bit;
365 }
366 }
367
John Stilesa976da72020-09-25 23:06:26 -0400368 ErrorReporter* fErrors;
John Stilesb21fac22020-12-04 15:36:49 -0500369 VariableReference* fAssignedVar = nullptr;
John Stilesdce4d3e2020-09-25 14:35:13 -0400370
371 using INHERITED = ProgramVisitor;
372};
373
John Stiles642cde22021-02-23 14:57:01 -0500374class SwitchCaseContainsExit : public ProgramVisitor {
375public:
376 SwitchCaseContainsExit(bool conditionalExits) : fConditionalExits(conditionalExits) {}
377
378 bool visitStatement(const Statement& stmt) override {
379 switch (stmt.kind()) {
380 case Statement::Kind::kBlock:
John Stilesa0e56e32021-03-03 13:14:37 -0500381 case Statement::Kind::kSwitchCase:
John Stiles642cde22021-02-23 14:57:01 -0500382 return INHERITED::visitStatement(stmt);
383
384 case Statement::Kind::kReturn:
385 // Returns are an early exit regardless of the surrounding control structures.
386 return fConditionalExits ? fInConditional : !fInConditional;
387
388 case Statement::Kind::kContinue:
389 // Continues are an early exit from switches, but not loops.
390 return !fInLoop &&
391 (fConditionalExits ? fInConditional : !fInConditional);
392
393 case Statement::Kind::kBreak:
394 // Breaks cannot escape from switches or loops.
395 return !fInLoop && !fInSwitch &&
396 (fConditionalExits ? fInConditional : !fInConditional);
397
398 case Statement::Kind::kIf: {
399 ++fInConditional;
400 bool result = INHERITED::visitStatement(stmt);
401 --fInConditional;
402 return result;
403 }
404
405 case Statement::Kind::kFor:
406 case Statement::Kind::kDo: {
407 // Loops are treated as conditionals because a loop could potentially execute zero
408 // times. We don't have a straightforward way to determine that a loop definitely
409 // executes at least once.
410 ++fInConditional;
411 ++fInLoop;
412 bool result = INHERITED::visitStatement(stmt);
413 --fInLoop;
414 --fInConditional;
415 return result;
416 }
417
418 case Statement::Kind::kSwitch: {
419 ++fInSwitch;
420 bool result = INHERITED::visitStatement(stmt);
421 --fInSwitch;
422 return result;
423 }
424
425 default:
426 return false;
427 }
428 }
429
430 bool fConditionalExits = false;
431 int fInConditional = 0;
432 int fInLoop = 0;
433 int fInSwitch = 0;
434 using INHERITED = ProgramVisitor;
435};
436
John Stilesb3dcbb12021-03-04 16:00:20 -0500437class ReturnsOnAllPathsVisitor : public ProgramVisitor {
438public:
439 bool visitExpression(const Expression& expr) override {
440 // We can avoid processing expressions entirely.
441 return false;
442 }
443
444 bool visitStatement(const Statement& stmt) override {
445 switch (stmt.kind()) {
446 // Returns, breaks, or continues will stop the scan, so only one of these should ever be
447 // true.
448 case Statement::Kind::kReturn:
449 fFoundReturn = true;
450 return true;
451
452 case Statement::Kind::kBreak:
453 fFoundBreak = true;
454 return true;
455
456 case Statement::Kind::kContinue:
457 fFoundContinue = true;
458 return true;
459
460 case Statement::Kind::kIf: {
461 const IfStatement& i = stmt.as<IfStatement>();
462 ReturnsOnAllPathsVisitor trueVisitor;
463 ReturnsOnAllPathsVisitor falseVisitor;
464 trueVisitor.visitStatement(*i.ifTrue());
465 if (i.ifFalse()) {
466 falseVisitor.visitStatement(*i.ifFalse());
467 }
468 // If either branch leads to a break or continue, we report the entire if as
469 // containing a break or continue, since we don't know which side will be reached.
470 fFoundBreak = (trueVisitor.fFoundBreak || falseVisitor.fFoundBreak);
471 fFoundContinue = (trueVisitor.fFoundContinue || falseVisitor.fFoundContinue);
472 // On the other hand, we only want to report returns that definitely happen, so we
473 // require those to be found on both sides.
474 fFoundReturn = (trueVisitor.fFoundReturn && falseVisitor.fFoundReturn);
475 return fFoundBreak || fFoundContinue || fFoundReturn;
476 }
477 case Statement::Kind::kFor: {
478 const ForStatement& f = stmt.as<ForStatement>();
479 // We assume a for/while loop runs for at least one iteration; this isn't strictly
480 // guaranteed, but it's better to be slightly over-permissive here than to fail on
481 // reasonable code.
482 ReturnsOnAllPathsVisitor forVisitor;
483 forVisitor.visitStatement(*f.statement());
484 // A for loop that contains a break or continue is safe; it won't exit the entire
485 // function, just the loop. So we disregard those signals.
486 fFoundReturn = forVisitor.fFoundReturn;
487 return fFoundReturn;
488 }
489 case Statement::Kind::kDo: {
490 const DoStatement& d = stmt.as<DoStatement>();
491 // Do-while blocks are always entered at least once.
492 ReturnsOnAllPathsVisitor doVisitor;
493 doVisitor.visitStatement(*d.statement());
494 // A do-while loop that contains a break or continue is safe; it won't exit the
495 // entire function, just the loop. So we disregard those signals.
496 fFoundReturn = doVisitor.fFoundReturn;
497 return fFoundReturn;
498 }
499 case Statement::Kind::kBlock:
500 // Blocks are definitely entered and don't imply any additional control flow.
501 // If the block contains a break, continue or return, we want to keep that.
502 return INHERITED::visitStatement(stmt);
503
504 case Statement::Kind::kSwitch: {
505 // Switches are the most complex control flow we need to deal with; fortunately we
506 // already have good primitives for dissecting them. We need to verify that:
507 // - a default case exists, so that every possible input value is covered
508 // - every switch-case either (a) returns unconditionally, or
509 // (b) falls through to another case that does
510 const SwitchStatement& s = stmt.as<SwitchStatement>();
511 bool foundDefault = false;
512 bool fellThrough = false;
John Stiles628777c2021-08-04 22:07:41 -0400513 for (const std::unique_ptr<Statement>& switchStmt : s.cases()) {
John Stilesb3dcbb12021-03-04 16:00:20 -0500514 // The default case is indicated by a null value. A switch without a default
515 // case cannot definitively return, as its value might not be in the cases list.
John Stiles628777c2021-08-04 22:07:41 -0400516 const SwitchCase& sc = switchStmt->as<SwitchCase>();
John Stilesb23a64b2021-03-11 08:27:59 -0500517 if (!sc.value()) {
John Stilesb3dcbb12021-03-04 16:00:20 -0500518 foundDefault = true;
519 }
520 // Scan this switch-case for any exit (break, continue or return).
521 ReturnsOnAllPathsVisitor caseVisitor;
John Stilesb23a64b2021-03-11 08:27:59 -0500522 caseVisitor.visitStatement(sc);
John Stilesb3dcbb12021-03-04 16:00:20 -0500523
524 // If we found a break or continue, whether conditional or not, this switch case
525 // can't be called an unconditional return. Switches absorb breaks but not
526 // continues.
527 if (caseVisitor.fFoundContinue) {
528 fFoundContinue = true;
529 return false;
530 }
531 if (caseVisitor.fFoundBreak) {
532 return false;
533 }
534 // We just confirmed that there weren't any breaks or continues. If we didn't
535 // find an unconditional return either, the switch is considered fallen-through.
536 // (There might be a conditional return, but that doesn't count.)
537 fellThrough = !caseVisitor.fFoundReturn;
538 }
539
540 // If we didn't find a default case, or the very last case fell through, this switch
541 // doesn't meet our criteria.
542 if (fellThrough || !foundDefault) {
543 return false;
544 }
545
546 // We scanned the entire switch, found a default case, and every section either fell
547 // through or contained an unconditional return.
548 fFoundReturn = true;
549 return true;
550 }
551
552 case Statement::Kind::kSwitchCase:
553 // Recurse into the switch-case.
554 return INHERITED::visitStatement(stmt);
555
556 case Statement::Kind::kDiscard:
557 case Statement::Kind::kExpression:
558 case Statement::Kind::kInlineMarker:
559 case Statement::Kind::kNop:
560 case Statement::Kind::kVarDeclaration:
561 // None of these statements could contain a return.
562 break;
563 }
564
565 return false;
566 }
567
568 bool fFoundReturn = false;
569 bool fFoundBreak = false;
570 bool fFoundContinue = false;
571
572 using INHERITED = ProgramVisitor;
573};
574
John Stilesa6841be2020-08-06 14:11:56 -0400575} // namespace
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400576
577////////////////////////////////////////////////////////////////////////////////
578// Analysis
579
Brian Osman4d571112021-04-27 09:10:10 -0400580SampleUsage Analysis::GetSampleUsage(const Program& program,
Brian Osman293497e2021-08-24 14:08:50 -0400581 const Variable& child,
Brian Osman8cdf28f2021-05-24 09:52:39 -0400582 bool writesToSampleCoords,
583 int* elidedSampleCoordCount) {
Brian Osman293497e2021-08-24 14:08:50 -0400584 MergeSampleUsageVisitor visitor(*program.fContext, child, writesToSampleCoords);
Brian Osman8cdf28f2021-05-24 09:52:39 -0400585 SampleUsage result = visitor.visit(program);
586 if (elidedSampleCoordCount) {
587 *elidedSampleCoordCount += visitor.elidedSampleCoordCount();
588 }
589 return result;
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400590}
591
Brian Osman92aac1e2020-08-05 16:48:58 -0400592bool Analysis::ReferencesBuiltin(const Program& program, int builtin) {
593 BuiltinVariableVisitor visitor(builtin);
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400594 return visitor.visit(program);
595}
596
Brian Osman92aac1e2020-08-05 16:48:58 -0400597bool Analysis::ReferencesSampleCoords(const Program& program) {
598 return Analysis::ReferencesBuiltin(program, SK_MAIN_COORDS_BUILTIN);
599}
600
601bool Analysis::ReferencesFragCoords(const Program& program) {
602 return Analysis::ReferencesBuiltin(program, SK_FRAGCOORD_BUILTIN);
603}
604
Brian Osman04d79fc2021-07-02 13:25:35 -0400605bool Analysis::CallsSampleOutsideMain(const Program& program) {
606 SampleOutsideMainVisitor visitor;
607 return visitor.visit(program);
608}
609
John Stiles61e5e202021-09-02 09:56:31 -0400610bool Analysis::CheckProgramUnrolledSize(const Program& program) {
611 // We check the size of strict-ES2 programs since SkVM will completely unroll them.
612 // Note that we *cannot* safely check the program size of non-ES2 code at this time, as it is
613 // allowed to do things we can't measure (e.g. the program can contain a recursive cycle). We
614 // could, at best, compute a lower bound.
615 const Context& context = *program.fContext;
616 SkASSERT(context.fConfig->strictES2Mode());
617
618 // If we decide that expressions are cheaper than statements, or that certain statements are
619 // more expensive than others, etc., we can always tweak these ratios as needed. A very rough
620 // ballpark estimate is currently good enough for our purposes.
John Stilesa047e8b2021-09-15 11:41:02 -0400621 static constexpr size_t kExpressionCost = 1;
622 static constexpr size_t kStatementCost = 1;
623 static constexpr size_t kUnknownCost = -1;
624 static constexpr size_t kProgramSizeLimit = 100000;
625 static constexpr size_t kProgramStackDepthLimit = 50;
John Stiles61e5e202021-09-02 09:56:31 -0400626
627 class ProgramSizeVisitor : public ProgramVisitor {
628 public:
John Stiles6475b102021-09-02 14:09:23 -0400629 ProgramSizeVisitor(const Context& c) : fContext(c) {}
John Stiles61e5e202021-09-02 09:56:31 -0400630
631 using ProgramVisitor::visitProgramElement;
632
John Stilesa047e8b2021-09-15 11:41:02 -0400633 size_t functionSize() const {
John Stiles6475b102021-09-02 14:09:23 -0400634 return fFunctionSize;
635 }
636
637 bool visitProgramElement(const ProgramElement& pe) override {
638 if (pe.is<FunctionDefinition>()) {
639 // Check the function-size cache map first. We don't need to visit this function if
640 // we already processed it before.
641 const FunctionDeclaration* decl = &pe.as<FunctionDefinition>().declaration();
642 auto [iter, wasInserted] = fFunctionCostMap.insert({decl, kUnknownCost});
643 if (!wasInserted) {
644 // We already have this function in our map. We don't need to check it again.
645 if (iter->second == kUnknownCost) {
646 // If the function is present in the map with an unknown cost, we're
647 // recursively processing it--in other words, we found a cycle in the code.
John Stiles98ddea02021-09-02 14:33:08 -0400648 // Unwind our stack into a string.
649 String msg = "\n\t" + decl->description();
650 for (auto unwind = fStack.rbegin(); unwind != fStack.rend(); ++unwind) {
651 msg = "\n\t" + (*unwind)->description() + msg;
652 if (*unwind == decl) {
653 break;
654 }
655 }
656 msg = "potential recursion (function call cycle) not allowed:" + msg;
Ethan Nicholas89cfde12021-09-27 11:20:34 -0400657 fContext.fErrors->error(pe.fLine, std::move(msg));
John Stiles6475b102021-09-02 14:09:23 -0400658 fFunctionSize = iter->second = 0;
659 return true;
660 }
661 // Set the size to its known value.
662 fFunctionSize = iter->second;
663 return false;
664 }
665
John Stiles2af4b132021-09-02 16:17:07 -0400666 // If the function-call stack has gotten too deep, stop the analysis.
667 if (fStack.size() >= kProgramStackDepthLimit) {
668 String msg = "exceeded max function call depth:";
669 for (auto unwind = fStack.begin(); unwind != fStack.end(); ++unwind) {
670 msg += "\n\t" + (*unwind)->description();
671 }
672 msg += "\n\t" + decl->description();
Ethan Nicholas89cfde12021-09-27 11:20:34 -0400673 fContext.fErrors->error(pe.fLine, std::move(msg));
John Stiles2af4b132021-09-02 16:17:07 -0400674 fFunctionSize = iter->second = 0;
675 return true;
676 }
677
John Stiles6475b102021-09-02 14:09:23 -0400678 // Calculate the function cost and store it in our cache.
John Stiles98ddea02021-09-02 14:33:08 -0400679 fStack.push_back(decl);
John Stiles6475b102021-09-02 14:09:23 -0400680 fFunctionSize = 0;
John Stiles6475b102021-09-02 14:09:23 -0400681 bool result = INHERITED::visitProgramElement(pe);
682 iter->second = fFunctionSize;
John Stiles98ddea02021-09-02 14:33:08 -0400683 fStack.pop_back();
684
John Stiles6475b102021-09-02 14:09:23 -0400685 return result;
686 }
687
688 return INHERITED::visitProgramElement(pe);
John Stiles61e5e202021-09-02 09:56:31 -0400689 }
690
691 bool visitStatement(const Statement& stmt) override {
692 switch (stmt.kind()) {
693 case Statement::Kind::kFor: {
694 // We count a for-loop's unrolled size here. We expect that the init statement
695 // will be emitted once, and the next-expr and statement will be repeated in the
696 // output for every iteration of the loop. The test-expr is optimized away
697 // during the unroll and is not counted at all.
698 const ForStatement& forStmt = stmt.as<ForStatement>();
John Stilesa047e8b2021-09-15 11:41:02 -0400699 bool result = this->visitStatement(*forStmt.initializer());
John Stiles61e5e202021-09-02 09:56:31 -0400700
John Stilesa047e8b2021-09-15 11:41:02 -0400701 size_t originalFunctionSize = fFunctionSize;
702 fFunctionSize = 0;
John Stiles61e5e202021-09-02 09:56:31 -0400703
John Stiles78b84cc2021-09-15 09:44:54 -0400704 result = this->visitExpression(*forStmt.next()) ||
705 this->visitStatement(*forStmt.statement()) || result;
John Stiles61e5e202021-09-02 09:56:31 -0400706
John Stilesa047e8b2021-09-15 11:41:02 -0400707 if (const LoopUnrollInfo* unrollInfo = forStmt.unrollInfo()) {
708 fFunctionSize = SkSafeMath::Mul(fFunctionSize, unrollInfo->fCount);
709 } else {
710 SkDEBUGFAIL("for-loops should always have unroll info in an ES2 program");
711 }
712
713 fFunctionSize = SkSafeMath::Add(fFunctionSize, originalFunctionSize);
John Stiles61e5e202021-09-02 09:56:31 -0400714 return result;
715 }
716
717 case Statement::Kind::kExpression:
718 // The cost of an expression-statement is counted in visitExpression. It would
719 // be double-dipping to count it here too.
720 break;
721
722 case Statement::Kind::kInlineMarker:
723 case Statement::Kind::kNop:
724 case Statement::Kind::kVarDeclaration:
725 // These statements don't directly consume any space in a compiled program.
726 break;
727
728 case Statement::Kind::kDo:
John Stiles61e5e202021-09-02 09:56:31 -0400729 SkDEBUGFAIL("encountered a statement that shouldn't exist in an ES2 program");
730 break;
731
732 default:
John Stilesa047e8b2021-09-15 11:41:02 -0400733 fFunctionSize = SkSafeMath::Add(fFunctionSize, kStatementCost);
John Stiles61e5e202021-09-02 09:56:31 -0400734 break;
735 }
736
John Stilesa047e8b2021-09-15 11:41:02 -0400737 bool earlyExit = fFunctionSize > kProgramSizeLimit;
738 return earlyExit || INHERITED::visitStatement(stmt);
John Stiles61e5e202021-09-02 09:56:31 -0400739 }
740
741 bool visitExpression(const Expression& expr) override {
742 // Other than function calls, all expressions are assumed to have a fixed unit cost.
John Stiles6475b102021-09-02 14:09:23 -0400743 bool earlyExit = false;
John Stilesa047e8b2021-09-15 11:41:02 -0400744 size_t expressionCost = kExpressionCost;
John Stiles61e5e202021-09-02 09:56:31 -0400745
746 if (expr.is<FunctionCall>()) {
John Stiles6475b102021-09-02 14:09:23 -0400747 // Visit this function call to calculate its size. If we've already sized it, this
748 // will retrieve the size from our cache.
John Stiles61e5e202021-09-02 09:56:31 -0400749 const FunctionCall& call = expr.as<FunctionCall>();
750 const FunctionDeclaration* decl = &call.function();
John Stiles61e5e202021-09-02 09:56:31 -0400751 if (decl->definition() && !decl->isIntrinsic()) {
John Stilesa047e8b2021-09-15 11:41:02 -0400752 size_t originalFunctionSize = fFunctionSize;
753 fFunctionSize = 0;
John Stiles61e5e202021-09-02 09:56:31 -0400754
John Stiles6475b102021-09-02 14:09:23 -0400755 earlyExit = this->visitProgramElement(*decl->definition());
756 expressionCost = fFunctionSize;
John Stiles61e5e202021-09-02 09:56:31 -0400757
John Stiles6475b102021-09-02 14:09:23 -0400758 fFunctionSize = originalFunctionSize;
John Stiles61e5e202021-09-02 09:56:31 -0400759 }
760 }
761
John Stilesa047e8b2021-09-15 11:41:02 -0400762 fFunctionSize = SkSafeMath::Add(fFunctionSize, expressionCost);
John Stiles6475b102021-09-02 14:09:23 -0400763 return earlyExit || INHERITED::visitExpression(expr);
John Stiles61e5e202021-09-02 09:56:31 -0400764 }
765
766 private:
767 using INHERITED = ProgramVisitor;
768
John Stiles36ddccc2021-09-03 10:57:04 -0400769 const Context& fContext;
John Stilesa047e8b2021-09-15 11:41:02 -0400770 size_t fFunctionSize = 0;
771 std::unordered_map<const FunctionDeclaration*, size_t> fFunctionCostMap;
John Stiles98ddea02021-09-02 14:33:08 -0400772 std::vector<const FunctionDeclaration*> fStack;
John Stiles61e5e202021-09-02 09:56:31 -0400773 };
774
John Stiles6475b102021-09-02 14:09:23 -0400775 // Process every function in our program.
776 ProgramSizeVisitor visitor{context};
John Stiles61e5e202021-09-02 09:56:31 -0400777 for (const std::unique_ptr<ProgramElement>& element : program.ownedElements()) {
John Stiles6475b102021-09-02 14:09:23 -0400778 if (element->is<FunctionDefinition>()) {
779 // Visit every function--we want to detect static recursion and report it as an error,
780 // even in unreferenced functions.
John Stiles61e5e202021-09-02 09:56:31 -0400781 visitor.visitProgramElement(*element);
John Stiles6475b102021-09-02 14:09:23 -0400782 // Report an error when main()'s flattened size is larger than our program limit.
783 if (visitor.functionSize() > kProgramSizeLimit &&
784 element->as<FunctionDefinition>().declaration().isMain()) {
Ethan Nicholas89cfde12021-09-27 11:20:34 -0400785 context.fErrors->error(/*line=*/-1, "program is too large");
John Stiles6475b102021-09-02 14:09:23 -0400786 }
John Stiles61e5e202021-09-02 09:56:31 -0400787 }
788 }
789
John Stiles61e5e202021-09-02 09:56:31 -0400790 return true;
791}
792
Ethan Nicholas98eae1e2021-09-01 14:37:29 -0400793bool Analysis::DetectVarDeclarationWithoutScope(const Statement& stmt, ErrorReporter* errors) {
794 // A variable declaration can create either a lone VarDeclaration or an unscoped Block
795 // containing multiple VarDeclaration statements. We need to detect either case.
796 const Variable* var;
797 if (stmt.is<VarDeclaration>()) {
798 // The single-variable case. No blocks at all.
799 var = &stmt.as<VarDeclaration>().var();
800 } else if (stmt.is<Block>()) {
801 // The multiple-variable case: an unscoped, non-empty block...
802 const Block& block = stmt.as<Block>();
803 if (block.isScope() || block.children().empty()) {
804 return false;
805 }
806 // ... holding a variable declaration.
807 const Statement& innerStmt = *block.children().front();
808 if (!innerStmt.is<VarDeclaration>()) {
809 return false;
810 }
811 var = &innerStmt.as<VarDeclaration>().var();
812 } else {
813 // This statement wasn't a variable declaration. No problem.
814 return false;
815 }
816
817 // Report an error.
818 SkASSERT(var);
819 if (errors) {
Ethan Nicholas89cfde12021-09-27 11:20:34 -0400820 errors->error(stmt.fLine, "variable '" + var->name() + "' must be created in a scope");
Ethan Nicholas98eae1e2021-09-01 14:37:29 -0400821 }
822 return true;
823}
824
John Stiles9b9415e2020-11-23 14:48:06 -0500825int Analysis::NodeCountUpToLimit(const FunctionDefinition& function, int limit) {
826 return NodeCountVisitor{limit}.visit(*function.body());
Ethan Nicholas6e0fa402020-08-20 14:08:23 -0400827}
828
John Stiles642cde22021-02-23 14:57:01 -0500829bool Analysis::SwitchCaseContainsUnconditionalExit(Statement& stmt) {
830 return SwitchCaseContainsExit{/*conditionalExits=*/false}.visitStatement(stmt);
831}
832
833bool Analysis::SwitchCaseContainsConditionalExit(Statement& stmt) {
834 return SwitchCaseContainsExit{/*conditionalExits=*/true}.visitStatement(stmt);
835}
836
Brian Osman010ce6a2020-10-19 16:34:10 -0400837std::unique_ptr<ProgramUsage> Analysis::GetUsage(const Program& program) {
838 auto usage = std::make_unique<ProgramUsage>();
839 ProgramUsageVisitor addRefs(usage.get(), /*delta=*/+1);
840 addRefs.visit(program);
841 return usage;
842}
843
Brian Osman0006ad02020-11-18 15:38:39 -0500844std::unique_ptr<ProgramUsage> Analysis::GetUsage(const LoadedModule& module) {
845 auto usage = std::make_unique<ProgramUsage>();
846 ProgramUsageVisitor addRefs(usage.get(), /*delta=*/+1);
847 for (const auto& element : module.fElements) {
848 addRefs.visitProgramElement(*element);
849 }
850 return usage;
851}
852
Brian Osman010ce6a2020-10-19 16:34:10 -0400853ProgramUsage::VariableCounts ProgramUsage::get(const Variable& v) const {
John Stiles04a8a542021-03-10 19:03:26 -0500854 const VariableCounts* counts = fVariableCounts.find(&v);
855 SkASSERT(counts);
856 return *counts;
Brian Osman010ce6a2020-10-19 16:34:10 -0400857}
858
859bool ProgramUsage::isDead(const Variable& v) const {
860 const Modifiers& modifiers = v.modifiers();
861 VariableCounts counts = this->get(v);
862 if ((v.storage() != Variable::Storage::kLocal && counts.fRead) ||
Brian Osmane49703f2021-04-19 11:15:24 -0400863 (modifiers.fFlags &
864 (Modifiers::kIn_Flag | Modifiers::kOut_Flag | Modifiers::kUniform_Flag))) {
Brian Osman010ce6a2020-10-19 16:34:10 -0400865 return false;
866 }
John Stilesf10eff32021-03-16 10:57:55 -0400867 // Consider the variable dead if it's never read and never written (besides the initial-value).
868 return !counts.fRead && (counts.fWrite <= (v.initialValue() ? 1 : 0));
Brian Osman010ce6a2020-10-19 16:34:10 -0400869}
870
871int ProgramUsage::get(const FunctionDeclaration& f) const {
872 const int* count = fCallCounts.find(&f);
873 return count ? *count : 0;
874}
875
John Stiles60dbf072021-08-02 14:22:34 -0400876void ProgramUsage::add(const Expression* expr) {
877 ProgramUsageVisitor addRefs(this, /*delta=*/+1);
878 addRefs.visitExpression(*expr);
Brian Osman010ce6a2020-10-19 16:34:10 -0400879}
880
881void ProgramUsage::add(const Statement* stmt) {
882 ProgramUsageVisitor addRefs(this, /*delta=*/+1);
883 addRefs.visitStatement(*stmt);
884}
885
John Stiles60dbf072021-08-02 14:22:34 -0400886void ProgramUsage::add(const ProgramElement& element) {
887 ProgramUsageVisitor addRefs(this, /*delta=*/+1);
888 addRefs.visitProgramElement(element);
889}
890
Brian Osman010ce6a2020-10-19 16:34:10 -0400891void ProgramUsage::remove(const Expression* expr) {
892 ProgramUsageVisitor subRefs(this, /*delta=*/-1);
893 subRefs.visitExpression(*expr);
894}
895
896void ProgramUsage::remove(const Statement* stmt) {
897 ProgramUsageVisitor subRefs(this, /*delta=*/-1);
898 subRefs.visitStatement(*stmt);
899}
900
901void ProgramUsage::remove(const ProgramElement& element) {
902 ProgramUsageVisitor subRefs(this, /*delta=*/-1);
903 subRefs.visitProgramElement(element);
Brian Osman2e25ff42020-10-15 10:32:04 -0400904}
905
Ethan Nicholas765d2fe2020-08-26 08:29:55 -0400906bool Analysis::StatementWritesToVariable(const Statement& stmt, const Variable& var) {
907 return VariableWriteVisitor(&var).visit(stmt);
908}
909
John Stilesb21fac22020-12-04 15:36:49 -0500910bool Analysis::IsAssignable(Expression& expr, AssignmentInfo* info, ErrorReporter* errors) {
John Stilesa976da72020-09-25 23:06:26 -0400911 TrivialErrorReporter trivialErrors;
John Stilesb21fac22020-12-04 15:36:49 -0500912 return IsAssignableVisitor{errors ? errors : &trivialErrors}.visit(expr, info);
John Stilesdce4d3e2020-09-25 14:35:13 -0400913}
914
John Stilesbb8cf582021-08-26 23:34:59 -0400915bool Analysis::UpdateVariableRefKind(Expression* expr,
916 VariableReference::RefKind kind,
917 ErrorReporter* errors) {
John Stiles516704b2021-02-26 15:01:57 -0500918 Analysis::AssignmentInfo info;
919 if (!Analysis::IsAssignable(*expr, &info, errors)) {
920 return false;
921 }
922 if (!info.fAssignedVar) {
John Stilesbb8cf582021-08-26 23:34:59 -0400923 if (errors) {
Ethan Nicholas89cfde12021-09-27 11:20:34 -0400924 errors->error(expr->fLine, "can't assign to expression '" + expr->description() + "'");
John Stilesbb8cf582021-08-26 23:34:59 -0400925 }
John Stiles516704b2021-02-26 15:01:57 -0500926 return false;
927 }
928 info.fAssignedVar->setRefKind(kind);
929 return true;
930}
931
John Stilesc30fbca2020-11-19 16:25:49 -0500932bool Analysis::IsTrivialExpression(const Expression& expr) {
John Stiles7591d4b2021-09-13 13:32:06 -0400933 return expr.is<Literal>() ||
John Stilesc30fbca2020-11-19 16:25:49 -0500934 expr.is<VariableReference>() ||
935 (expr.is<Swizzle>() &&
936 IsTrivialExpression(*expr.as<Swizzle>().base())) ||
937 (expr.is<FieldAccess>() &&
938 IsTrivialExpression(*expr.as<FieldAccess>().base())) ||
John Stiles2938eea2021-04-01 18:58:25 -0400939 (expr.isAnyConstructor() &&
940 expr.asAnyConstructor().argumentSpan().size() == 1 &&
941 IsTrivialExpression(*expr.asAnyConstructor().argumentSpan().front())) ||
942 (expr.isAnyConstructor() &&
John Stilesc30fbca2020-11-19 16:25:49 -0500943 expr.isConstantOrUniform()) ||
944 (expr.is<IndexExpression>() &&
John Stiles7591d4b2021-09-13 13:32:06 -0400945 expr.as<IndexExpression>().index()->isIntLiteral() &&
John Stilesc30fbca2020-11-19 16:25:49 -0500946 IsTrivialExpression(*expr.as<IndexExpression>().base()));
947}
948
John Stiles5676c572021-03-08 17:10:52 -0500949bool Analysis::IsSameExpressionTree(const Expression& left, const Expression& right) {
John Stiles95d0bad2021-03-01 17:02:28 -0500950 if (left.kind() != right.kind() || left.type() != right.type()) {
951 return false;
952 }
953
John Stiles5676c572021-03-08 17:10:52 -0500954 // This isn't a fully exhaustive list of expressions by any stretch of the imagination; for
955 // instance, `x[y+1] = x[y+1]` isn't detected because we don't look at BinaryExpressions.
956 // Since this is intended to be used for optimization purposes, handling the common cases is
957 // sufficient.
John Stiles95d0bad2021-03-01 17:02:28 -0500958 switch (left.kind()) {
John Stiles7591d4b2021-09-13 13:32:06 -0400959 case Expression::Kind::kLiteral:
960 return left.as<Literal>().value() == right.as<Literal>().value();
John Stiles5676c572021-03-08 17:10:52 -0500961
John Stiles7384b372021-04-01 13:48:15 -0400962 case Expression::Kind::kConstructorArray:
John Stilese3ae9682021-08-05 10:35:01 -0400963 case Expression::Kind::kConstructorArrayCast:
John Stiles8cad6372021-04-07 12:31:13 -0400964 case Expression::Kind::kConstructorCompound:
965 case Expression::Kind::kConstructorCompoundCast:
John Stiles2938eea2021-04-01 18:58:25 -0400966 case Expression::Kind::kConstructorDiagonalMatrix:
John Stiles5abb9e12021-04-06 13:47:19 -0400967 case Expression::Kind::kConstructorMatrixResize:
John Stilesfd7252f2021-04-04 22:24:40 -0400968 case Expression::Kind::kConstructorScalarCast:
John Stilesd47330f2021-04-08 23:25:52 -0400969 case Expression::Kind::kConstructorStruct:
John Stiles268a73f2021-04-07 12:30:22 -0400970 case Expression::Kind::kConstructorSplat: {
John Stilesfd7252f2021-04-04 22:24:40 -0400971 if (left.kind() != right.kind()) {
972 return false;
973 }
John Stiles7384b372021-04-01 13:48:15 -0400974 const AnyConstructor& leftCtor = left.asAnyConstructor();
975 const AnyConstructor& rightCtor = right.asAnyConstructor();
976 const auto leftSpan = leftCtor.argumentSpan();
977 const auto rightSpan = rightCtor.argumentSpan();
978 if (leftSpan.size() != rightSpan.size()) {
John Stiles5676c572021-03-08 17:10:52 -0500979 return false;
980 }
John Stiles7384b372021-04-01 13:48:15 -0400981 for (size_t index = 0; index < leftSpan.size(); ++index) {
982 if (!IsSameExpressionTree(*leftSpan[index], *rightSpan[index])) {
John Stiles5676c572021-03-08 17:10:52 -0500983 return false;
984 }
985 }
986 return true;
987 }
John Stiles95d0bad2021-03-01 17:02:28 -0500988 case Expression::Kind::kFieldAccess:
989 return left.as<FieldAccess>().fieldIndex() == right.as<FieldAccess>().fieldIndex() &&
John Stiles5676c572021-03-08 17:10:52 -0500990 IsSameExpressionTree(*left.as<FieldAccess>().base(),
991 *right.as<FieldAccess>().base());
John Stiles95d0bad2021-03-01 17:02:28 -0500992
993 case Expression::Kind::kIndex:
John Stiles5676c572021-03-08 17:10:52 -0500994 return IsSameExpressionTree(*left.as<IndexExpression>().index(),
995 *right.as<IndexExpression>().index()) &&
996 IsSameExpressionTree(*left.as<IndexExpression>().base(),
997 *right.as<IndexExpression>().base());
John Stiles95d0bad2021-03-01 17:02:28 -0500998
999 case Expression::Kind::kSwizzle:
1000 return left.as<Swizzle>().components() == right.as<Swizzle>().components() &&
John Stiles5676c572021-03-08 17:10:52 -05001001 IsSameExpressionTree(*left.as<Swizzle>().base(), *right.as<Swizzle>().base());
John Stiles95d0bad2021-03-01 17:02:28 -05001002
1003 case Expression::Kind::kVariableReference:
1004 return left.as<VariableReference>().variable() ==
1005 right.as<VariableReference>().variable();
1006
1007 default:
1008 return false;
1009 }
1010}
1011
Ethan Nicholas89cfde12021-09-27 11:20:34 -04001012static const char* invalid_for_ES2(int line,
John Stiles232b4ce2021-03-01 22:14:22 -05001013 const Statement* loopInitializer,
1014 const Expression* loopTest,
1015 const Expression* loopNext,
1016 const Statement* loopStatement,
John Stiles9c975c52021-08-31 10:18:57 -04001017 LoopUnrollInfo& loopInfo) {
Brian Osman77ba8102021-01-12 17:15:30 -05001018 //
1019 // init_declaration has the form: type_specifier identifier = constant_expression
1020 //
John Stiles232b4ce2021-03-01 22:14:22 -05001021 if (!loopInitializer) {
Brian Osman77ba8102021-01-12 17:15:30 -05001022 return "missing init declaration";
1023 }
John Stiles232b4ce2021-03-01 22:14:22 -05001024 if (!loopInitializer->is<VarDeclaration>()) {
Brian Osman77ba8102021-01-12 17:15:30 -05001025 return "invalid init declaration";
1026 }
John Stiles232b4ce2021-03-01 22:14:22 -05001027 const VarDeclaration& initDecl = loopInitializer->as<VarDeclaration>();
Brian Osman6c7910e2021-01-14 09:50:52 -05001028 if (!initDecl.baseType().isNumber()) {
Brian Osman77ba8102021-01-12 17:15:30 -05001029 return "invalid type for loop index";
1030 }
1031 if (initDecl.arraySize() != 0) {
1032 return "invalid type for loop index";
1033 }
1034 if (!initDecl.value()) {
1035 return "missing loop index initializer";
1036 }
Brian Osman448b2d52021-09-23 11:36:15 -04001037 if (!ConstantFolder::GetConstantValue(*initDecl.value(), &loopInfo.fStart)) {
Brian Osman77ba8102021-01-12 17:15:30 -05001038 return "loop index initializer must be a constant expression";
1039 }
1040
1041 loopInfo.fIndex = &initDecl.var();
1042
1043 auto is_loop_index = [&](const std::unique_ptr<Expression>& expr) {
1044 return expr->is<VariableReference>() &&
1045 expr->as<VariableReference>().variable() == loopInfo.fIndex;
1046 };
1047
1048 //
1049 // condition has the form: loop_index relational_operator constant_expression
1050 //
John Stiles232b4ce2021-03-01 22:14:22 -05001051 if (!loopTest) {
Brian Osman77ba8102021-01-12 17:15:30 -05001052 return "missing condition";
1053 }
John Stiles232b4ce2021-03-01 22:14:22 -05001054 if (!loopTest->is<BinaryExpression>()) {
Brian Osman77ba8102021-01-12 17:15:30 -05001055 return "invalid condition";
1056 }
John Stiles232b4ce2021-03-01 22:14:22 -05001057 const BinaryExpression& cond = loopTest->as<BinaryExpression>();
Brian Osman77ba8102021-01-12 17:15:30 -05001058 if (!is_loop_index(cond.left())) {
1059 return "expected loop index on left hand side of condition";
1060 }
1061 // relational_operator is one of: > >= < <= == or !=
John Stiles45990502021-02-16 10:55:27 -05001062 switch (cond.getOperator().kind()) {
Brian Osman77ba8102021-01-12 17:15:30 -05001063 case Token::Kind::TK_GT:
1064 case Token::Kind::TK_GTEQ:
1065 case Token::Kind::TK_LT:
1066 case Token::Kind::TK_LTEQ:
1067 case Token::Kind::TK_EQEQ:
1068 case Token::Kind::TK_NEQ:
1069 break;
1070 default:
1071 return "invalid relational operator";
1072 }
1073 double loopEnd = 0;
Brian Osman448b2d52021-09-23 11:36:15 -04001074 if (!ConstantFolder::GetConstantValue(*cond.right(), &loopEnd)) {
Brian Osman77ba8102021-01-12 17:15:30 -05001075 return "loop index must be compared with a constant expression";
1076 }
1077
1078 //
1079 // expression has one of the following forms:
1080 // loop_index++
1081 // loop_index--
1082 // loop_index += constant_expression
1083 // loop_index -= constant_expression
1084 // The spec doesn't mention prefix increment and decrement, but there is some consensus that
1085 // it's an oversight, so we allow those as well.
1086 //
John Stiles232b4ce2021-03-01 22:14:22 -05001087 if (!loopNext) {
Brian Osman77ba8102021-01-12 17:15:30 -05001088 return "missing loop expression";
1089 }
John Stiles232b4ce2021-03-01 22:14:22 -05001090 switch (loopNext->kind()) {
Brian Osman77ba8102021-01-12 17:15:30 -05001091 case Expression::Kind::kBinary: {
John Stiles232b4ce2021-03-01 22:14:22 -05001092 const BinaryExpression& next = loopNext->as<BinaryExpression>();
Brian Osman77ba8102021-01-12 17:15:30 -05001093 if (!is_loop_index(next.left())) {
1094 return "expected loop index in loop expression";
1095 }
Brian Osman448b2d52021-09-23 11:36:15 -04001096 if (!ConstantFolder::GetConstantValue(*next.right(), &loopInfo.fDelta)) {
Brian Osman77ba8102021-01-12 17:15:30 -05001097 return "loop index must be modified by a constant expression";
1098 }
John Stiles45990502021-02-16 10:55:27 -05001099 switch (next.getOperator().kind()) {
Brian Osman77ba8102021-01-12 17:15:30 -05001100 case Token::Kind::TK_PLUSEQ: break;
1101 case Token::Kind::TK_MINUSEQ: loopInfo.fDelta = -loopInfo.fDelta; break;
1102 default:
1103 return "invalid operator in loop expression";
1104 }
1105 } break;
1106 case Expression::Kind::kPrefix: {
John Stiles232b4ce2021-03-01 22:14:22 -05001107 const PrefixExpression& next = loopNext->as<PrefixExpression>();
Brian Osman77ba8102021-01-12 17:15:30 -05001108 if (!is_loop_index(next.operand())) {
1109 return "expected loop index in loop expression";
1110 }
John Stiles45990502021-02-16 10:55:27 -05001111 switch (next.getOperator().kind()) {
Brian Osman77ba8102021-01-12 17:15:30 -05001112 case Token::Kind::TK_PLUSPLUS: loopInfo.fDelta = 1; break;
1113 case Token::Kind::TK_MINUSMINUS: loopInfo.fDelta = -1; break;
1114 default:
1115 return "invalid operator in loop expression";
1116 }
1117 } break;
1118 case Expression::Kind::kPostfix: {
John Stiles232b4ce2021-03-01 22:14:22 -05001119 const PostfixExpression& next = loopNext->as<PostfixExpression>();
Brian Osman77ba8102021-01-12 17:15:30 -05001120 if (!is_loop_index(next.operand())) {
1121 return "expected loop index in loop expression";
1122 }
John Stiles45990502021-02-16 10:55:27 -05001123 switch (next.getOperator().kind()) {
Brian Osman77ba8102021-01-12 17:15:30 -05001124 case Token::Kind::TK_PLUSPLUS: loopInfo.fDelta = 1; break;
1125 case Token::Kind::TK_MINUSMINUS: loopInfo.fDelta = -1; break;
1126 default:
1127 return "invalid operator in loop expression";
1128 }
1129 } break;
1130 default:
1131 return "invalid loop expression";
1132 }
1133
1134 //
1135 // Within the body of the loop, the loop index is not statically assigned to, nor is it used as
1136 // argument to a function 'out' or 'inout' parameter.
1137 //
John Stiles232b4ce2021-03-01 22:14:22 -05001138 if (Analysis::StatementWritesToVariable(*loopStatement, initDecl.var())) {
Brian Osman77ba8102021-01-12 17:15:30 -05001139 return "loop index must not be modified within body of the loop";
1140 }
1141
1142 // Finally, compute the iteration count, based on the bounds, and the termination operator.
John Stiles106e0cd2021-09-07 11:43:51 -04001143 static constexpr int kLoopTerminationLimit = 100000;
Brian Osman77ba8102021-01-12 17:15:30 -05001144 loopInfo.fCount = 0;
1145
John Stiles106e0cd2021-09-07 11:43:51 -04001146 auto calculateCount = [](double start, double end, double delta,
1147 bool forwards, bool inclusive) -> int {
1148 if (forwards != (start < end)) {
1149 // The loop starts in a completed state (the start has already advanced past the end).
1150 return 0;
Brian Osman77ba8102021-01-12 17:15:30 -05001151 }
John Stiles106e0cd2021-09-07 11:43:51 -04001152 if ((delta == 0.0) || forwards != (delta > 0.0)) {
1153 // The loop does not progress toward a completed state, and will never terminate.
1154 return kLoopTerminationLimit;
1155 }
1156 double iterations = sk_ieee_double_divide(end - start, delta);
1157 double count = std::ceil(iterations);
1158 if (inclusive && (count == iterations)) {
1159 count += 1.0;
1160 }
1161 if (count > kLoopTerminationLimit || !std::isfinite(count)) {
1162 // The loop runs for more iterations than we can safely unroll.
1163 return kLoopTerminationLimit;
1164 }
1165 return (int)count;
Brian Osman77ba8102021-01-12 17:15:30 -05001166 };
1167
John Stiles106e0cd2021-09-07 11:43:51 -04001168 switch (cond.getOperator().kind()) {
1169 case Token::Kind::TK_LT:
1170 loopInfo.fCount = calculateCount(loopInfo.fStart, loopEnd, loopInfo.fDelta,
1171 /*forwards=*/true, /*inclusive=*/false);
1172 break;
1173
1174 case Token::Kind::TK_GT:
1175 loopInfo.fCount = calculateCount(loopInfo.fStart, loopEnd, loopInfo.fDelta,
1176 /*forwards=*/false, /*inclusive=*/false);
1177 break;
1178
1179 case Token::Kind::TK_LTEQ:
1180 loopInfo.fCount = calculateCount(loopInfo.fStart, loopEnd, loopInfo.fDelta,
1181 /*forwards=*/true, /*inclusive=*/true);
1182 break;
1183
1184 case Token::Kind::TK_GTEQ:
1185 loopInfo.fCount = calculateCount(loopInfo.fStart, loopEnd, loopInfo.fDelta,
1186 /*forwards=*/false, /*inclusive=*/true);
1187 break;
1188
1189 case Token::Kind::TK_NEQ: {
1190 float iterations = sk_ieee_double_divide(loopEnd - loopInfo.fStart, loopInfo.fDelta);
1191 loopInfo.fCount = std::ceil(iterations);
1192 if (loopInfo.fCount < 0 || loopInfo.fCount != iterations ||
1193 !std::isfinite(iterations)) {
1194 // The loop doesn't reach the exact endpoint and so will never terminate.
1195 loopInfo.fCount = kLoopTerminationLimit;
1196 }
Brian Osman77ba8102021-01-12 17:15:30 -05001197 break;
1198 }
John Stiles106e0cd2021-09-07 11:43:51 -04001199 case Token::Kind::TK_EQEQ: {
1200 if (loopInfo.fStart == loopEnd) {
1201 // Start and end begin in the same place, so we can run one iteration...
1202 if (loopInfo.fDelta) {
1203 // ... and then they diverge, so the loop terminates.
1204 loopInfo.fCount = 1;
1205 } else {
1206 // ... but they never diverge, so the loop runs forever.
1207 loopInfo.fCount = kLoopTerminationLimit;
1208 }
1209 } else {
1210 // Start never equals end, so the loop will not run a single iteration.
1211 loopInfo.fCount = 0;
1212 }
1213 break;
1214 }
1215 default: SkUNREACHABLE;
Brian Osman77ba8102021-01-12 17:15:30 -05001216 }
1217
John Stiles106e0cd2021-09-07 11:43:51 -04001218 SkASSERT(loopInfo.fCount >= 0);
1219 if (loopInfo.fCount >= kLoopTerminationLimit) {
Brian Osman77ba8102021-01-12 17:15:30 -05001220 return "loop must guarantee termination in fewer iterations";
1221 }
1222
1223 return nullptr; // All checks pass
1224}
1225
Ethan Nicholas89cfde12021-09-27 11:20:34 -04001226std::unique_ptr<LoopUnrollInfo> Analysis::GetLoopUnrollInfo(int line,
John Stiles9c975c52021-08-31 10:18:57 -04001227 const Statement* loopInitializer,
1228 const Expression* loopTest,
1229 const Expression* loopNext,
1230 const Statement* loopStatement,
1231 ErrorReporter* errors) {
1232 auto result = std::make_unique<LoopUnrollInfo>();
Ethan Nicholas89cfde12021-09-27 11:20:34 -04001233 if (const char* msg = invalid_for_ES2(line, loopInitializer, loopTest, loopNext,
John Stiles9c975c52021-08-31 10:18:57 -04001234 loopStatement, *result)) {
1235 result = nullptr;
Brian Osman77ba8102021-01-12 17:15:30 -05001236 if (errors) {
Ethan Nicholas89cfde12021-09-27 11:20:34 -04001237 errors->error(line, msg);
Brian Osman77ba8102021-01-12 17:15:30 -05001238 }
Brian Osman77ba8102021-01-12 17:15:30 -05001239 }
John Stiles9c975c52021-08-31 10:18:57 -04001240 return result;
Brian Osman77ba8102021-01-12 17:15:30 -05001241}
1242
Brian Osman7b361492021-02-25 11:25:30 -05001243// Checks for ES2 constant-expression rules, and (optionally) constant-index-expression rules
1244// (if loopIndices is non-nullptr)
1245class ConstantExpressionVisitor : public ProgramVisitor {
Brian Osmanea485e52021-01-15 13:20:32 -05001246public:
Brian Osman7b361492021-02-25 11:25:30 -05001247 ConstantExpressionVisitor(const std::set<const Variable*>* loopIndices)
Brian Osmanea485e52021-01-15 13:20:32 -05001248 : fLoopIndices(loopIndices) {}
1249
1250 bool visitExpression(const Expression& e) override {
1251 // A constant-(index)-expression is one of...
1252 switch (e.kind()) {
1253 // ... a literal value
John Stiles7591d4b2021-09-13 13:32:06 -04001254 case Expression::Kind::kLiteral:
Brian Osmanea485e52021-01-15 13:20:32 -05001255 return false;
1256
John Stiles532138c2021-03-04 16:29:22 -05001257 // ... settings can appear in fragment processors; they will resolve when compiled
1258 case Expression::Kind::kSetting:
1259 return false;
1260
Brian Osman7b361492021-02-25 11:25:30 -05001261 // ... a global or local variable qualified as 'const', excluding function parameters.
1262 // ... loop indices as defined in section 4. [constant-index-expression]
1263 case Expression::Kind::kVariableReference: {
1264 const Variable* v = e.as<VariableReference>().variable();
1265 if ((v->storage() == Variable::Storage::kGlobal ||
1266 v->storage() == Variable::Storage::kLocal) &&
1267 (v->modifiers().fFlags & Modifiers::kConst_Flag)) {
1268 return false;
1269 }
1270 return !fLoopIndices || fLoopIndices->find(v) == fLoopIndices->end();
1271 }
Brian Osmanea485e52021-01-15 13:20:32 -05001272
1273 // ... expressions composed of both of the above
1274 case Expression::Kind::kBinary:
John Stiles7384b372021-04-01 13:48:15 -04001275 case Expression::Kind::kConstructorArray:
John Stilese3ae9682021-08-05 10:35:01 -04001276 case Expression::Kind::kConstructorArrayCast:
John Stiles8cad6372021-04-07 12:31:13 -04001277 case Expression::Kind::kConstructorCompound:
1278 case Expression::Kind::kConstructorCompoundCast:
John Stilese1182782021-03-30 22:09:37 -04001279 case Expression::Kind::kConstructorDiagonalMatrix:
John Stiles5abb9e12021-04-06 13:47:19 -04001280 case Expression::Kind::kConstructorMatrixResize:
John Stilesfd7252f2021-04-04 22:24:40 -04001281 case Expression::Kind::kConstructorScalarCast:
John Stiles2938eea2021-04-01 18:58:25 -04001282 case Expression::Kind::kConstructorSplat:
John Stilesd47330f2021-04-08 23:25:52 -04001283 case Expression::Kind::kConstructorStruct:
Brian Osmanea485e52021-01-15 13:20:32 -05001284 case Expression::Kind::kFieldAccess:
1285 case Expression::Kind::kIndex:
1286 case Expression::Kind::kPrefix:
1287 case Expression::Kind::kPostfix:
1288 case Expression::Kind::kSwizzle:
1289 case Expression::Kind::kTernary:
1290 return INHERITED::visitExpression(e);
1291
John Stiles7bd3f1c2021-08-27 16:12:10 -04001292 // Function calls are completely disallowed in SkSL constant-(index)-expressions.
1293 // GLSL does mandate that calling a built-in function where the arguments are all
1294 // constant-expressions should result in a constant-expression. SkSL handles this by
1295 // optimizing fully-constant function calls into literals in FunctionCall::Make.
Brian Osmanea485e52021-01-15 13:20:32 -05001296 case Expression::Kind::kFunctionCall:
John Stiles7bd3f1c2021-08-27 16:12:10 -04001297 case Expression::Kind::kExternalFunctionCall:
1298 case Expression::Kind::kChildCall:
Brian Osmanea485e52021-01-15 13:20:32 -05001299
John Stiles7bd3f1c2021-08-27 16:12:10 -04001300 // These shouldn't appear in a valid program at all, and definitely aren't
1301 // constant-index-expressions.
Ethan Nicholas549c6b82021-06-25 12:31:44 -04001302 case Expression::Kind::kPoison:
John Stiles7bd3f1c2021-08-27 16:12:10 -04001303 case Expression::Kind::kFunctionReference:
1304 case Expression::Kind::kExternalFunctionReference:
Brian Osman3099f792021-09-01 13:12:16 -04001305 case Expression::Kind::kMethodReference:
John Stiles7bd3f1c2021-08-27 16:12:10 -04001306 case Expression::Kind::kTypeReference:
1307 case Expression::Kind::kCodeString:
Ethan Nicholas549c6b82021-06-25 12:31:44 -04001308 return true;
1309
Brian Osmanea485e52021-01-15 13:20:32 -05001310 default:
1311 SkDEBUGFAIL("Unexpected expression type");
1312 return true;
1313 }
1314 }
1315
1316private:
1317 const std::set<const Variable*>* fLoopIndices;
1318 using INHERITED = ProgramVisitor;
1319};
1320
1321class ES2IndexingVisitor : public ProgramVisitor {
1322public:
1323 ES2IndexingVisitor(ErrorReporter& errors) : fErrors(errors) {}
1324
1325 bool visitStatement(const Statement& s) override {
1326 if (s.is<ForStatement>()) {
1327 const ForStatement& f = s.as<ForStatement>();
1328 SkASSERT(f.initializer() && f.initializer()->is<VarDeclaration>());
1329 const Variable* var = &f.initializer()->as<VarDeclaration>().var();
1330 auto [iter, inserted] = fLoopIndices.insert(var);
1331 SkASSERT(inserted);
1332 bool result = this->visitStatement(*f.statement());
1333 fLoopIndices.erase(iter);
1334 return result;
1335 }
1336 return INHERITED::visitStatement(s);
1337 }
1338
1339 bool visitExpression(const Expression& e) override {
1340 if (e.is<IndexExpression>()) {
1341 const IndexExpression& i = e.as<IndexExpression>();
Brian Osman7b361492021-02-25 11:25:30 -05001342 ConstantExpressionVisitor indexerInvalid(&fLoopIndices);
Brian Osmanea485e52021-01-15 13:20:32 -05001343 if (indexerInvalid.visitExpression(*i.index())) {
Ethan Nicholas89cfde12021-09-27 11:20:34 -04001344 fErrors.error(i.fLine, "index expression must be constant");
Brian Osmanea485e52021-01-15 13:20:32 -05001345 return true;
1346 }
1347 }
1348 return INHERITED::visitExpression(e);
1349 }
1350
1351 using ProgramVisitor::visitProgramElement;
1352
1353private:
1354 ErrorReporter& fErrors;
1355 std::set<const Variable*> fLoopIndices;
1356 using INHERITED = ProgramVisitor;
1357};
1358
1359
1360void Analysis::ValidateIndexingForES2(const ProgramElement& pe, ErrorReporter& errors) {
1361 ES2IndexingVisitor visitor(errors);
1362 visitor.visitProgramElement(pe);
1363}
1364
Brian Osman7b361492021-02-25 11:25:30 -05001365bool Analysis::IsConstantExpression(const Expression& expr) {
1366 ConstantExpressionVisitor visitor(/*loopIndices=*/nullptr);
1367 return !visitor.visitExpression(expr);
1368}
1369
John Stiles958f4b52021-03-17 16:39:49 -04001370bool Analysis::CanExitWithoutReturningValue(const FunctionDeclaration& funcDecl,
1371 const Statement& body) {
1372 if (funcDecl.returnType().isVoid()) {
1373 return false;
1374 }
John Stilesb3dcbb12021-03-04 16:00:20 -05001375 ReturnsOnAllPathsVisitor visitor;
John Stiles958f4b52021-03-17 16:39:49 -04001376 visitor.visitStatement(body);
John Stilesb3dcbb12021-03-04 16:00:20 -05001377 return !visitor.fFoundReturn;
1378}
1379
John Stiles2ecc5952021-09-01 14:41:36 -04001380void Analysis::VerifyStaticTestsAndExpressions(const Program& program) {
1381 class TestsAndExpressions : public ProgramVisitor {
John Stiles0fc6bed2021-09-01 11:35:59 -04001382 public:
John Stiles2ecc5952021-09-01 14:41:36 -04001383 TestsAndExpressions(const Context& ctx) : fContext(ctx) {}
John Stiles0fc6bed2021-09-01 11:35:59 -04001384
1385 using ProgramVisitor::visitProgramElement;
1386
1387 bool visitStatement(const Statement& stmt) override {
John Stiles2ecc5952021-09-01 14:41:36 -04001388 if (!fContext.fConfig->fSettings.fPermitInvalidStaticTests) {
1389 switch (stmt.kind()) {
1390 case Statement::Kind::kIf:
1391 if (stmt.as<IfStatement>().isStatic()) {
Ethan Nicholas89cfde12021-09-27 11:20:34 -04001392 fContext.fErrors->error(stmt.fLine, "static if has non-static test");
John Stiles2ecc5952021-09-01 14:41:36 -04001393 }
1394 break;
John Stiles0fc6bed2021-09-01 11:35:59 -04001395
John Stiles2ecc5952021-09-01 14:41:36 -04001396 case Statement::Kind::kSwitch:
1397 if (stmt.as<SwitchStatement>().isStatic()) {
Ethan Nicholas89cfde12021-09-27 11:20:34 -04001398 fContext.fErrors->error(stmt.fLine,
John Stiles2ecc5952021-09-01 14:41:36 -04001399 "static switch has non-static test");
1400 }
1401 break;
John Stiles0fc6bed2021-09-01 11:35:59 -04001402
John Stiles2ecc5952021-09-01 14:41:36 -04001403 default:
1404 break;
1405 }
John Stiles0fc6bed2021-09-01 11:35:59 -04001406 }
1407 return INHERITED::visitStatement(stmt);
1408 }
1409
John Stiles2ecc5952021-09-01 14:41:36 -04001410 bool visitExpression(const Expression& expr) override {
1411 switch (expr.kind()) {
1412 case Expression::Kind::kFunctionCall: {
1413 const FunctionDeclaration& decl = expr.as<FunctionCall>().function();
1414 if (!decl.isBuiltin() && !decl.definition()) {
Ethan Nicholas89cfde12021-09-27 11:20:34 -04001415 fContext.fErrors->error(expr.fLine, "function '" + decl.description() +
1416 "' is not defined");
John Stiles2ecc5952021-09-01 14:41:36 -04001417 }
1418 break;
1419 }
1420 case Expression::Kind::kExternalFunctionReference:
1421 case Expression::Kind::kFunctionReference:
Brian Osman3099f792021-09-01 13:12:16 -04001422 case Expression::Kind::kMethodReference:
John Stiles2ecc5952021-09-01 14:41:36 -04001423 case Expression::Kind::kTypeReference:
1424 SkDEBUGFAIL("invalid reference-expr, should have been reported by coerce()");
Ethan Nicholas89cfde12021-09-27 11:20:34 -04001425 fContext.fErrors->error(expr.fLine, "invalid expression");
John Stiles2ecc5952021-09-01 14:41:36 -04001426 break;
1427 default:
1428 if (expr.type() == *fContext.fTypes.fInvalid) {
Ethan Nicholas89cfde12021-09-27 11:20:34 -04001429 fContext.fErrors->error(expr.fLine, "invalid expression");
John Stiles2ecc5952021-09-01 14:41:36 -04001430 }
1431 break;
1432 }
1433 return INHERITED::visitExpression(expr);
John Stiles0fc6bed2021-09-01 11:35:59 -04001434 }
1435
1436 private:
1437 using INHERITED = ProgramVisitor;
John Stiles2ecc5952021-09-01 14:41:36 -04001438 const Context& fContext;
John Stiles0fc6bed2021-09-01 11:35:59 -04001439 };
1440
John Stiles0fc6bed2021-09-01 11:35:59 -04001441 // Check all of the program's owned elements. (Built-in elements are assumed to be valid.)
John Stiles2ecc5952021-09-01 14:41:36 -04001442 TestsAndExpressions visitor{*program.fContext};
John Stiles0fc6bed2021-09-01 11:35:59 -04001443 for (const std::unique_ptr<ProgramElement>& element : program.ownedElements()) {
John Stiles2ecc5952021-09-01 14:41:36 -04001444 visitor.visitProgramElement(*element);
John Stiles0fc6bed2021-09-01 11:35:59 -04001445 }
1446}
1447
John Stiles49b1a422021-09-22 09:35:39 -04001448void Analysis::EliminateUnreachableCode(std::unique_ptr<Statement>& stmt, ProgramUsage* usage) {
1449 class UnreachableCodeEliminator : public ProgramWriter {
1450 public:
1451 UnreachableCodeEliminator(ProgramUsage* usage)
1452 : fUsage(usage) {
1453 fFoundFunctionExit.push(false);
1454 fFoundLoopExit.push(false);
1455 }
1456
1457 bool visitExpressionPtr(std::unique_ptr<Expression>& expr) override {
1458 // We don't need to look inside expressions at all.
1459 return false;
1460 }
1461
1462 bool visitStatementPtr(std::unique_ptr<Statement>& stmt) override {
1463 if (fFoundFunctionExit.top() || fFoundLoopExit.top()) {
1464 // If we already found an exit in this section, anything beyond it is dead code.
1465 if (!stmt->is<Nop>()) {
1466 // Eliminate the dead statement by substituting a Nop.
1467 if (fUsage) {
1468 fUsage->remove(stmt.get());
1469 }
1470 stmt = std::make_unique<Nop>();
1471 }
1472 return false;
1473 }
1474
1475 switch (stmt->kind()) {
1476 case Statement::Kind::kReturn:
1477 case Statement::Kind::kDiscard:
1478 // We found a function exit on this path.
1479 fFoundFunctionExit.top() = true;
1480 break;
1481
1482 case Statement::Kind::kBreak:
1483 case Statement::Kind::kContinue:
1484 // We found a loop exit on this path. Note that we skip over switch statements
1485 // completely when eliminating code, so any `break` statement would be breaking
1486 // out of a loop, not out of a switch.
1487 fFoundLoopExit.top() = true;
1488 break;
1489
1490 case Statement::Kind::kExpression:
1491 case Statement::Kind::kInlineMarker:
1492 case Statement::Kind::kNop:
1493 case Statement::Kind::kVarDeclaration:
1494 // These statements don't affect control flow.
1495 break;
1496
1497 case Statement::Kind::kBlock:
1498 // Blocks are on the straight-line path and don't affect control flow.
1499 return INHERITED::visitStatementPtr(stmt);
1500
1501 case Statement::Kind::kDo: {
1502 // Function-exits are allowed to propagate outside of a do-loop, because it
1503 // always executes its body at least once.
1504 fFoundLoopExit.push(false);
1505 bool result = INHERITED::visitStatementPtr(stmt);
1506 fFoundLoopExit.pop();
1507 return result;
1508 }
1509 case Statement::Kind::kFor: {
1510 // Function-exits are not allowed to propagate out, because a for-loop or while-
1511 // loop could potentially run zero times.
1512 fFoundFunctionExit.push(false);
1513 fFoundLoopExit.push(false);
1514 bool result = INHERITED::visitStatementPtr(stmt);
1515 fFoundLoopExit.pop();
1516 fFoundFunctionExit.pop();
1517 return result;
1518 }
1519 case Statement::Kind::kIf: {
1520 // This statement is conditional and encloses two inner sections of code.
1521 // If both sides contain a function-exit or loop-exit, that exit is allowed to
1522 // propagate out.
1523 IfStatement& ifStmt = stmt->as<IfStatement>();
1524
1525 fFoundFunctionExit.push(false);
1526 fFoundLoopExit.push(false);
1527 bool result = (ifStmt.ifTrue() && this->visitStatementPtr(ifStmt.ifTrue()));
1528 bool foundFunctionExitOnTrue = fFoundFunctionExit.top();
1529 bool foundLoopExitOnTrue = fFoundLoopExit.top();
1530 fFoundFunctionExit.pop();
1531 fFoundLoopExit.pop();
1532
1533 fFoundFunctionExit.push(false);
1534 fFoundLoopExit.push(false);
1535 result |= (ifStmt.ifFalse() && this->visitStatementPtr(ifStmt.ifFalse()));
1536 bool foundFunctionExitOnFalse = fFoundFunctionExit.top();
1537 bool foundLoopExitOnFalse = fFoundLoopExit.top();
1538 fFoundFunctionExit.pop();
1539 fFoundLoopExit.pop();
1540
1541 fFoundFunctionExit.top() |= foundFunctionExitOnTrue && foundFunctionExitOnFalse;
1542 fFoundLoopExit.top() |= foundLoopExitOnTrue && foundLoopExitOnFalse;
1543 return result;
1544 }
1545 case Statement::Kind::kSwitch:
1546 case Statement::Kind::kSwitchCase:
1547 // We skip past switch statements entirely when scanning for dead code. Their
1548 // control flow is quite complex and we already do a good job of flattening out
1549 // switches on constant values.
1550 break;
1551 }
1552
1553 return false;
1554 }
1555
1556 ProgramUsage* fUsage;
1557 std::stack<bool> fFoundFunctionExit;
1558 std::stack<bool> fFoundLoopExit;
1559
1560 using INHERITED = ProgramWriter;
1561 };
1562
1563 UnreachableCodeEliminator visitor{usage};
1564 visitor.visitStatementPtr(stmt);
1565}
1566
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001567////////////////////////////////////////////////////////////////////////////////
1568// ProgramVisitor
1569
Brian Osman133724c2020-10-28 14:14:39 -04001570bool ProgramVisitor::visit(const Program& program) {
1571 for (const ProgramElement* pe : program.elements()) {
Brian Osman1179fcf2020-10-08 16:04:40 -04001572 if (this->visitProgramElement(*pe)) {
John Stiles933abe32020-08-28 11:58:40 -04001573 return true;
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001574 }
1575 }
John Stiles933abe32020-08-28 11:58:40 -04001576 return false;
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001577}
1578
John Stiles48b25582021-03-11 14:26:42 -05001579template <typename T> bool TProgramVisitor<T>::visitExpression(typename T::Expression& e) {
John Stiles70b82422020-09-30 10:55:12 -04001580 switch (e.kind()) {
John Stiles6d023462021-10-06 12:51:10 -04001581 case Expression::Kind::kCodeString:
Brian Osmanbe0b3b72021-01-06 14:27:35 -05001582 case Expression::Kind::kExternalFunctionReference:
Ethan Nicholase6592142020-09-08 10:22:09 -04001583 case Expression::Kind::kFunctionReference:
John Stiles7591d4b2021-09-13 13:32:06 -04001584 case Expression::Kind::kLiteral:
Brian Osman3099f792021-09-01 13:12:16 -04001585 case Expression::Kind::kMethodReference:
Ethan Nicholas549c6b82021-06-25 12:31:44 -04001586 case Expression::Kind::kPoison:
Ethan Nicholase6592142020-09-08 10:22:09 -04001587 case Expression::Kind::kSetting:
1588 case Expression::Kind::kTypeReference:
1589 case Expression::Kind::kVariableReference:
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001590 // Leaf expressions return false
1591 return false;
John Stiles70b82422020-09-30 10:55:12 -04001592
Ethan Nicholase6592142020-09-08 10:22:09 -04001593 case Expression::Kind::kBinary: {
John Stiles70b82422020-09-30 10:55:12 -04001594 auto& b = e.template as<BinaryExpression>();
John Stiles48b25582021-03-11 14:26:42 -05001595 return (b.left() && this->visitExpressionPtr(b.left())) ||
1596 (b.right() && this->visitExpressionPtr(b.right()));
John Stiles70b82422020-09-30 10:55:12 -04001597 }
Brian Osmaneb0f29d2021-08-04 11:34:16 -04001598 case Expression::Kind::kChildCall: {
1599 // We don't visit the child variable itself, just the arguments
1600 auto& c = e.template as<ChildCall>();
1601 for (auto& arg : c.arguments()) {
1602 if (arg && this->visitExpressionPtr(arg)) { return true; }
1603 }
1604 return false;
1605 }
John Stiles7384b372021-04-01 13:48:15 -04001606 case Expression::Kind::kConstructorArray:
John Stilese3ae9682021-08-05 10:35:01 -04001607 case Expression::Kind::kConstructorArrayCast:
John Stiles8cad6372021-04-07 12:31:13 -04001608 case Expression::Kind::kConstructorCompound:
1609 case Expression::Kind::kConstructorCompoundCast:
John Stiles2938eea2021-04-01 18:58:25 -04001610 case Expression::Kind::kConstructorDiagonalMatrix:
John Stiles5abb9e12021-04-06 13:47:19 -04001611 case Expression::Kind::kConstructorMatrixResize:
John Stilesfd7252f2021-04-04 22:24:40 -04001612 case Expression::Kind::kConstructorScalarCast:
John Stilesd47330f2021-04-08 23:25:52 -04001613 case Expression::Kind::kConstructorSplat:
1614 case Expression::Kind::kConstructorStruct: {
John Stiles7384b372021-04-01 13:48:15 -04001615 auto& c = e.asAnyConstructor();
1616 for (auto& arg : c.argumentSpan()) {
John Stiles48b25582021-03-11 14:26:42 -05001617 if (this->visitExpressionPtr(arg)) { return true; }
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001618 }
John Stiles70b82422020-09-30 10:55:12 -04001619 return false;
1620 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001621 case Expression::Kind::kExternalFunctionCall: {
John Stiles70b82422020-09-30 10:55:12 -04001622 auto& c = e.template as<ExternalFunctionCall>();
Ethan Nicholas6e86ec92020-09-30 14:29:56 -04001623 for (auto& arg : c.arguments()) {
John Stiles48b25582021-03-11 14:26:42 -05001624 if (this->visitExpressionPtr(arg)) { return true; }
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001625 }
John Stiles70b82422020-09-30 10:55:12 -04001626 return false;
1627 }
John Stilesd7ab4502020-09-24 22:41:00 -04001628 case Expression::Kind::kFieldAccess:
John Stiles48b25582021-03-11 14:26:42 -05001629 return this->visitExpressionPtr(e.template as<FieldAccess>().base());
John Stiles70b82422020-09-30 10:55:12 -04001630
Ethan Nicholase6592142020-09-08 10:22:09 -04001631 case Expression::Kind::kFunctionCall: {
John Stiles70b82422020-09-30 10:55:12 -04001632 auto& c = e.template as<FunctionCall>();
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001633 for (auto& arg : c.arguments()) {
John Stiles48b25582021-03-11 14:26:42 -05001634 if (arg && this->visitExpressionPtr(arg)) { return true; }
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001635 }
John Stiles70b82422020-09-30 10:55:12 -04001636 return false;
1637 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001638 case Expression::Kind::kIndex: {
John Stiles70b82422020-09-30 10:55:12 -04001639 auto& i = e.template as<IndexExpression>();
John Stiles48b25582021-03-11 14:26:42 -05001640 return this->visitExpressionPtr(i.base()) || this->visitExpressionPtr(i.index());
John Stiles70b82422020-09-30 10:55:12 -04001641 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001642 case Expression::Kind::kPostfix:
John Stiles48b25582021-03-11 14:26:42 -05001643 return this->visitExpressionPtr(e.template as<PostfixExpression>().operand());
John Stiles70b82422020-09-30 10:55:12 -04001644
Ethan Nicholase6592142020-09-08 10:22:09 -04001645 case Expression::Kind::kPrefix:
John Stiles48b25582021-03-11 14:26:42 -05001646 return this->visitExpressionPtr(e.template as<PrefixExpression>().operand());
John Stiles70b82422020-09-30 10:55:12 -04001647
Brian Osman010ce6a2020-10-19 16:34:10 -04001648 case Expression::Kind::kSwizzle: {
1649 auto& s = e.template as<Swizzle>();
John Stiles48b25582021-03-11 14:26:42 -05001650 return s.base() && this->visitExpressionPtr(s.base());
Brian Osman010ce6a2020-10-19 16:34:10 -04001651 }
John Stiles70b82422020-09-30 10:55:12 -04001652
Ethan Nicholase6592142020-09-08 10:22:09 -04001653 case Expression::Kind::kTernary: {
John Stiles70b82422020-09-30 10:55:12 -04001654 auto& t = e.template as<TernaryExpression>();
John Stiles48b25582021-03-11 14:26:42 -05001655 return this->visitExpressionPtr(t.test()) ||
1656 (t.ifTrue() && this->visitExpressionPtr(t.ifTrue())) ||
1657 (t.ifFalse() && this->visitExpressionPtr(t.ifFalse()));
John Stiles70b82422020-09-30 10:55:12 -04001658 }
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001659 default:
1660 SkUNREACHABLE;
1661 }
1662}
1663
John Stiles48b25582021-03-11 14:26:42 -05001664template <typename T> bool TProgramVisitor<T>::visitStatement(typename T::Statement& s) {
John Stiles70b82422020-09-30 10:55:12 -04001665 switch (s.kind()) {
Ethan Nicholase6592142020-09-08 10:22:09 -04001666 case Statement::Kind::kBreak:
1667 case Statement::Kind::kContinue:
1668 case Statement::Kind::kDiscard:
John Stiles98c1f822020-09-09 14:18:53 -04001669 case Statement::Kind::kInlineMarker:
Ethan Nicholase6592142020-09-08 10:22:09 -04001670 case Statement::Kind::kNop:
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001671 // Leaf statements just return false
1672 return false;
John Stiles70b82422020-09-30 10:55:12 -04001673
Ethan Nicholase6592142020-09-08 10:22:09 -04001674 case Statement::Kind::kBlock:
John Stiles70b82422020-09-30 10:55:12 -04001675 for (auto& stmt : s.template as<Block>().children()) {
John Stiles48b25582021-03-11 14:26:42 -05001676 if (stmt && this->visitStatementPtr(stmt)) {
Ethan Nicholas7bd60432020-09-25 14:31:59 -04001677 return true;
1678 }
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001679 }
1680 return false;
John Stiles70b82422020-09-30 10:55:12 -04001681
John Stilesa0e56e32021-03-03 13:14:37 -05001682 case Statement::Kind::kSwitchCase: {
1683 auto& sc = s.template as<SwitchCase>();
John Stiles48b25582021-03-11 14:26:42 -05001684 if (sc.value() && this->visitExpressionPtr(sc.value())) {
John Stilesa0e56e32021-03-03 13:14:37 -05001685 return true;
1686 }
John Stiles48b25582021-03-11 14:26:42 -05001687 return this->visitStatementPtr(sc.statement());
John Stilesa0e56e32021-03-03 13:14:37 -05001688 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001689 case Statement::Kind::kDo: {
John Stiles70b82422020-09-30 10:55:12 -04001690 auto& d = s.template as<DoStatement>();
John Stiles48b25582021-03-11 14:26:42 -05001691 return this->visitExpressionPtr(d.test()) || this->visitStatementPtr(d.statement());
John Stiles70b82422020-09-30 10:55:12 -04001692 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001693 case Statement::Kind::kExpression:
John Stiles48b25582021-03-11 14:26:42 -05001694 return this->visitExpressionPtr(s.template as<ExpressionStatement>().expression());
John Stiles70b82422020-09-30 10:55:12 -04001695
Ethan Nicholase6592142020-09-08 10:22:09 -04001696 case Statement::Kind::kFor: {
John Stiles70b82422020-09-30 10:55:12 -04001697 auto& f = s.template as<ForStatement>();
John Stiles48b25582021-03-11 14:26:42 -05001698 return (f.initializer() && this->visitStatementPtr(f.initializer())) ||
1699 (f.test() && this->visitExpressionPtr(f.test())) ||
1700 (f.next() && this->visitExpressionPtr(f.next())) ||
1701 this->visitStatementPtr(f.statement());
John Stiles70b82422020-09-30 10:55:12 -04001702 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001703 case Statement::Kind::kIf: {
John Stiles70b82422020-09-30 10:55:12 -04001704 auto& i = s.template as<IfStatement>();
John Stiles48b25582021-03-11 14:26:42 -05001705 return (i.test() && this->visitExpressionPtr(i.test())) ||
1706 (i.ifTrue() && this->visitStatementPtr(i.ifTrue())) ||
1707 (i.ifFalse() && this->visitStatementPtr(i.ifFalse()));
John Stiles70b82422020-09-30 10:55:12 -04001708 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001709 case Statement::Kind::kReturn: {
John Stiles70b82422020-09-30 10:55:12 -04001710 auto& r = s.template as<ReturnStatement>();
John Stiles48b25582021-03-11 14:26:42 -05001711 return r.expression() && this->visitExpressionPtr(r.expression());
John Stiles70b82422020-09-30 10:55:12 -04001712 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001713 case Statement::Kind::kSwitch: {
John Stiles70b82422020-09-30 10:55:12 -04001714 auto& sw = s.template as<SwitchStatement>();
John Stiles48b25582021-03-11 14:26:42 -05001715 if (this->visitExpressionPtr(sw.value())) {
John Stiles70b82422020-09-30 10:55:12 -04001716 return true;
1717 }
John Stiles48b25582021-03-11 14:26:42 -05001718 for (auto& c : sw.cases()) {
1719 if (this->visitStatementPtr(c)) {
John Stiles70b82422020-09-30 10:55:12 -04001720 return true;
1721 }
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001722 }
John Stiles70b82422020-09-30 10:55:12 -04001723 return false;
1724 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001725 case Statement::Kind::kVarDeclaration: {
John Stiles70b82422020-09-30 10:55:12 -04001726 auto& v = s.template as<VarDeclaration>();
John Stiles48b25582021-03-11 14:26:42 -05001727 return v.value() && this->visitExpressionPtr(v.value());
John Stiles70b82422020-09-30 10:55:12 -04001728 }
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001729 default:
1730 SkUNREACHABLE;
1731 }
1732}
1733
John Stiles48b25582021-03-11 14:26:42 -05001734template <typename T> bool TProgramVisitor<T>::visitProgramElement(typename T::ProgramElement& pe) {
John Stiles70b82422020-09-30 10:55:12 -04001735 switch (pe.kind()) {
Ethan Nicholase6592142020-09-08 10:22:09 -04001736 case ProgramElement::Kind::kExtension:
John Stiles569249b2020-11-03 12:18:22 -05001737 case ProgramElement::Kind::kFunctionPrototype:
John Stilesd39aec02020-12-03 10:42:26 -05001738 case ProgramElement::Kind::kInterfaceBlock:
Ethan Nicholase6592142020-09-08 10:22:09 -04001739 case ProgramElement::Kind::kModifiers:
John Stilesdc75a972020-11-25 16:24:55 -05001740 case ProgramElement::Kind::kStructDefinition:
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001741 // Leaf program elements just return false by default
1742 return false;
John Stiles70b82422020-09-30 10:55:12 -04001743
Ethan Nicholase6592142020-09-08 10:22:09 -04001744 case ProgramElement::Kind::kFunction:
John Stiles48b25582021-03-11 14:26:42 -05001745 return this->visitStatementPtr(pe.template as<FunctionDefinition>().body());
John Stiles70b82422020-09-30 10:55:12 -04001746
Brian Osmanc0213602020-10-06 14:43:32 -04001747 case ProgramElement::Kind::kGlobalVar:
John Stiles48b25582021-03-11 14:26:42 -05001748 return this->visitStatementPtr(pe.template as<GlobalVarDeclaration>().declaration());
John Stiles70b82422020-09-30 10:55:12 -04001749
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001750 default:
1751 SkUNREACHABLE;
1752 }
1753}
1754
John Stiles48b25582021-03-11 14:26:42 -05001755template class TProgramVisitor<ProgramVisitorTypes>;
1756template class TProgramVisitor<ProgramWriterTypes>;
John Stiles70b82422020-09-30 10:55:12 -04001757
John Stilesa6841be2020-08-06 14:11:56 -04001758} // namespace SkSL