blob: dd44f77084db1371d56c0ddfde7f49d7ab681ec8 [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"
Brian Osman00185012021-02-04 16:07:11 -050016#include "src/sksl/SkSLCompiler.h"
Brian Osman448b2d52021-09-23 11:36:15 -040017#include "src/sksl/SkSLConstantFolder.h"
Ethan Nicholas17807552021-10-01 09:42:36 -040018#include "src/sksl/analysis/SkSLProgramVisitor.h"
Michael Ludwig8f3a8362020-06-29 17:27:00 -040019#include "src/sksl/ir/SkSLExpression.h"
20#include "src/sksl/ir/SkSLProgram.h"
Ethan Nicholas17807552021-10-01 09:42:36 -040021#include "src/sksl/transform/SkSLProgramWriter.h"
Michael Ludwig8f3a8362020-06-29 17:27:00 -040022
23// ProgramElements
Michael Ludwig8f3a8362020-06-29 17:27:00 -040024#include "src/sksl/ir/SkSLExtension.h"
25#include "src/sksl/ir/SkSLFunctionDefinition.h"
26#include "src/sksl/ir/SkSLInterfaceBlock.h"
Michael Ludwig8f3a8362020-06-29 17:27:00 -040027#include "src/sksl/ir/SkSLVarDeclarations.h"
28
29// Statements
30#include "src/sksl/ir/SkSLBlock.h"
31#include "src/sksl/ir/SkSLBreakStatement.h"
32#include "src/sksl/ir/SkSLContinueStatement.h"
33#include "src/sksl/ir/SkSLDiscardStatement.h"
34#include "src/sksl/ir/SkSLDoStatement.h"
35#include "src/sksl/ir/SkSLExpressionStatement.h"
36#include "src/sksl/ir/SkSLForStatement.h"
37#include "src/sksl/ir/SkSLIfStatement.h"
38#include "src/sksl/ir/SkSLNop.h"
39#include "src/sksl/ir/SkSLReturnStatement.h"
40#include "src/sksl/ir/SkSLSwitchStatement.h"
Michael Ludwig8f3a8362020-06-29 17:27:00 -040041
42// Expressions
43#include "src/sksl/ir/SkSLBinaryExpression.h"
Brian Osmaneb0f29d2021-08-04 11:34:16 -040044#include "src/sksl/ir/SkSLChildCall.h"
Michael Ludwig8f3a8362020-06-29 17:27:00 -040045#include "src/sksl/ir/SkSLConstructor.h"
John Stilese1182782021-03-30 22:09:37 -040046#include "src/sksl/ir/SkSLConstructorDiagonalMatrix.h"
John Stiles5abb9e12021-04-06 13:47:19 -040047#include "src/sksl/ir/SkSLConstructorMatrixResize.h"
Michael Ludwig8f3a8362020-06-29 17:27:00 -040048#include "src/sksl/ir/SkSLExternalFunctionCall.h"
Brian Osmanbe0b3b72021-01-06 14:27:35 -050049#include "src/sksl/ir/SkSLExternalFunctionReference.h"
Michael Ludwig8f3a8362020-06-29 17:27:00 -040050#include "src/sksl/ir/SkSLFieldAccess.h"
Michael Ludwig8f3a8362020-06-29 17:27:00 -040051#include "src/sksl/ir/SkSLFunctionCall.h"
52#include "src/sksl/ir/SkSLFunctionReference.h"
53#include "src/sksl/ir/SkSLIndexExpression.h"
John Stiles98c1f822020-09-09 14:18:53 -040054#include "src/sksl/ir/SkSLInlineMarker.h"
John Stiles7591d4b2021-09-13 13:32:06 -040055#include "src/sksl/ir/SkSLLiteral.h"
Michael Ludwig8f3a8362020-06-29 17:27:00 -040056#include "src/sksl/ir/SkSLPostfixExpression.h"
57#include "src/sksl/ir/SkSLPrefixExpression.h"
58#include "src/sksl/ir/SkSLSetting.h"
59#include "src/sksl/ir/SkSLSwizzle.h"
60#include "src/sksl/ir/SkSLTernaryExpression.h"
61#include "src/sksl/ir/SkSLTypeReference.h"
62#include "src/sksl/ir/SkSLVariableReference.h"
63
64namespace SkSL {
65
66namespace {
67
Brian Osmaneb0f29d2021-08-04 11:34:16 -040068// Visitor that determines the merged SampleUsage for a given child in the program.
Brian Osman1298bc42020-06-30 13:39:35 -040069class MergeSampleUsageVisitor : public ProgramVisitor {
Michael Ludwig8f3a8362020-06-29 17:27:00 -040070public:
Brian Osmaneb0f29d2021-08-04 11:34:16 -040071 MergeSampleUsageVisitor(const Context& context,
72 const Variable& child,
73 bool writesToSampleCoords)
74 : fContext(context), fChild(child), fWritesToSampleCoords(writesToSampleCoords) {}
Michael Ludwig8f3a8362020-06-29 17:27:00 -040075
Brian Osman1298bc42020-06-30 13:39:35 -040076 SampleUsage visit(const Program& program) {
77 fUsage = SampleUsage(); // reset to none
John Stilesd7ab4502020-09-24 22:41:00 -040078 INHERITED::visit(program);
Brian Osman1298bc42020-06-30 13:39:35 -040079 return fUsage;
Michael Ludwig8f3a8362020-06-29 17:27:00 -040080 }
81
Brian Osman8cdf28f2021-05-24 09:52:39 -040082 int elidedSampleCoordCount() const { return fElidedSampleCoordCount; }
83
Michael Ludwig8f3a8362020-06-29 17:27:00 -040084protected:
John Stiles933abe32020-08-28 11:58:40 -040085 const Context& fContext;
Brian Osmaneb0f29d2021-08-04 11:34:16 -040086 const Variable& fChild;
Brian Osman4d571112021-04-27 09:10:10 -040087 const bool fWritesToSampleCoords;
Brian Osman1298bc42020-06-30 13:39:35 -040088 SampleUsage fUsage;
Brian Osman8cdf28f2021-05-24 09:52:39 -040089 int fElidedSampleCoordCount = 0;
Michael Ludwig8f3a8362020-06-29 17:27:00 -040090
91 bool visitExpression(const Expression& e) override {
Brian Osmaneb0f29d2021-08-04 11:34:16 -040092 // Looking for child(...)
93 if (e.is<ChildCall>() && &e.as<ChildCall>().child() == &fChild) {
94 // Determine the type of call at this site, and merge it with the accumulated state
95 const ExpressionArray& arguments = e.as<ChildCall>().arguments();
96 SkASSERT(arguments.size() >= 1);
97
98 const Expression* maybeCoords = arguments[0].get();
99 if (maybeCoords->type() == *fContext.fTypes.fFloat2) {
100 // If the coords are a direct reference to the program's sample-coords, and those
101 // coords are never modified, we can conservatively turn this into PassThrough
102 // sampling. In all other cases, we consider it Explicit.
103 if (!fWritesToSampleCoords && maybeCoords->is<VariableReference>() &&
104 maybeCoords->as<VariableReference>().variable()->modifiers().fLayout.fBuiltin ==
105 SK_MAIN_COORDS_BUILTIN) {
Brian Osman1298bc42020-06-30 13:39:35 -0400106 fUsage.merge(SampleUsage::PassThrough());
Brian Osmaneb0f29d2021-08-04 11:34:16 -0400107 ++fElidedSampleCoordCount;
108 } else {
109 fUsage.merge(SampleUsage::Explicit());
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400110 }
Brian Osmaneb0f29d2021-08-04 11:34:16 -0400111 } else {
112 // child(inputColor) or child(srcColor, dstColor) -> PassThrough
113 fUsage.merge(SampleUsage::PassThrough());
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400114 }
115 }
116
John Stilesd7ab4502020-09-24 22:41:00 -0400117 return INHERITED::visitExpression(e);
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400118 }
119
John Stiles7571f9e2020-09-02 22:42:33 -0400120 using INHERITED = ProgramVisitor;
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400121};
122
Brian Osman92aac1e2020-08-05 16:48:58 -0400123// Visitor that searches through the program for references to a particular builtin variable
124class BuiltinVariableVisitor : public ProgramVisitor {
125public:
126 BuiltinVariableVisitor(int builtin) : fBuiltin(builtin) {}
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400127
128 bool visitExpression(const Expression& e) override {
Brian Osman79457ef2020-09-24 15:01:27 -0400129 if (e.is<VariableReference>()) {
John Stiles403a3632020-08-20 12:11:48 -0400130 const VariableReference& var = e.as<VariableReference>();
Ethan Nicholas78686922020-10-08 06:46:27 -0400131 return var.variable()->modifiers().fLayout.fBuiltin == fBuiltin;
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400132 }
John Stilesd7ab4502020-09-24 22:41:00 -0400133 return INHERITED::visitExpression(e);
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400134 }
135
Brian Osman92aac1e2020-08-05 16:48:58 -0400136 int fBuiltin;
137
John Stiles7571f9e2020-09-02 22:42:33 -0400138 using INHERITED = ProgramVisitor;
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400139};
140
Brian Osmaneb0f29d2021-08-04 11:34:16 -0400141// Visitor that searches for child calls from a function other than main()
Brian Osman04d79fc2021-07-02 13:25:35 -0400142class SampleOutsideMainVisitor : public ProgramVisitor {
143public:
144 SampleOutsideMainVisitor() {}
145
146 bool visitExpression(const Expression& e) override {
Brian Osmaneb0f29d2021-08-04 11:34:16 -0400147 if (e.is<ChildCall>()) {
148 return true;
Brian Osman04d79fc2021-07-02 13:25:35 -0400149 }
150 return INHERITED::visitExpression(e);
151 }
152
153 bool visitProgramElement(const ProgramElement& p) override {
154 return p.is<FunctionDefinition>() &&
155 !p.as<FunctionDefinition>().declaration().isMain() &&
156 INHERITED::visitProgramElement(p);
157 }
158
159 using INHERITED = ProgramVisitor;
160};
161
Ethan Nicholas6e0fa402020-08-20 14:08:23 -0400162// Visitor that counts the number of nodes visited
163class NodeCountVisitor : public ProgramVisitor {
164public:
John Stiles2c1e4922020-10-01 09:14:14 -0400165 NodeCountVisitor(int limit) : fLimit(limit) {}
166
Ethan Nicholas6e0fa402020-08-20 14:08:23 -0400167 int visit(const Statement& s) {
Ethan Nicholas6e0fa402020-08-20 14:08:23 -0400168 this->visitStatement(s);
169 return fCount;
170 }
171
172 bool visitExpression(const Expression& e) override {
173 ++fCount;
John Stiles9b9415e2020-11-23 14:48:06 -0500174 return (fCount >= fLimit) || INHERITED::visitExpression(e);
Ethan Nicholas6e0fa402020-08-20 14:08:23 -0400175 }
176
177 bool visitProgramElement(const ProgramElement& p) override {
178 ++fCount;
John Stiles9b9415e2020-11-23 14:48:06 -0500179 return (fCount >= fLimit) || INHERITED::visitProgramElement(p);
Ethan Nicholas6e0fa402020-08-20 14:08:23 -0400180 }
181
182 bool visitStatement(const Statement& s) override {
183 ++fCount;
John Stiles9b9415e2020-11-23 14:48:06 -0500184 return (fCount >= fLimit) || INHERITED::visitStatement(s);
Ethan Nicholas6e0fa402020-08-20 14:08:23 -0400185 }
186
187private:
John Stiles2c1e4922020-10-01 09:14:14 -0400188 int fCount = 0;
189 int fLimit;
Ethan Nicholas6e0fa402020-08-20 14:08:23 -0400190
John Stiles7571f9e2020-09-02 22:42:33 -0400191 using INHERITED = ProgramVisitor;
Ethan Nicholas6e0fa402020-08-20 14:08:23 -0400192};
193
Ethan Nicholas765d2fe2020-08-26 08:29:55 -0400194class VariableWriteVisitor : public ProgramVisitor {
195public:
196 VariableWriteVisitor(const Variable* var)
197 : fVar(var) {}
198
199 bool visit(const Statement& s) {
200 return this->visitStatement(s);
201 }
202
203 bool visitExpression(const Expression& e) override {
Brian Osman79457ef2020-09-24 15:01:27 -0400204 if (e.is<VariableReference>()) {
Ethan Nicholas765d2fe2020-08-26 08:29:55 -0400205 const VariableReference& ref = e.as<VariableReference>();
Ethan Nicholas453f67f2020-10-09 10:43:45 -0400206 if (ref.variable() == fVar &&
207 (ref.refKind() == VariableReference::RefKind::kWrite ||
208 ref.refKind() == VariableReference::RefKind::kReadWrite ||
209 ref.refKind() == VariableReference::RefKind::kPointer)) {
Ethan Nicholas765d2fe2020-08-26 08:29:55 -0400210 return true;
211 }
212 }
John Stilesd7ab4502020-09-24 22:41:00 -0400213 return INHERITED::visitExpression(e);
Ethan Nicholas765d2fe2020-08-26 08:29:55 -0400214 }
215
216private:
217 const Variable* fVar;
218
John Stiles7571f9e2020-09-02 22:42:33 -0400219 using INHERITED = ProgramVisitor;
Ethan Nicholas765d2fe2020-08-26 08:29:55 -0400220};
221
John Stilesa976da72020-09-25 23:06:26 -0400222// If a caller doesn't care about errors, we can use this trivial reporter that just counts up.
223class TrivialErrorReporter : public ErrorReporter {
224public:
John Stilesbb8cf582021-08-26 23:34:59 -0400225 ~TrivialErrorReporter() override { this->reportPendingErrors({}); }
Ethan Nicholas32724122021-09-07 13:49:07 -0400226 void handleError(skstd::string_view, PositionInfo) override {}
John Stilesa976da72020-09-25 23:06:26 -0400227};
228
John Stilesdce4d3e2020-09-25 14:35:13 -0400229// This isn't actually using ProgramVisitor, because it only considers a subset of the fields for
230// any given expression kind. For instance, when indexing an array (e.g. `x[1]`), we only want to
231// know if the base (`x`) is assignable; the index expression (`1`) doesn't need to be.
232class IsAssignableVisitor {
233public:
John Stilesb21fac22020-12-04 15:36:49 -0500234 IsAssignableVisitor(ErrorReporter* errors) : fErrors(errors) {}
John Stilesdce4d3e2020-09-25 14:35:13 -0400235
John Stilesb21fac22020-12-04 15:36:49 -0500236 bool visit(Expression& expr, Analysis::AssignmentInfo* info) {
Ethan Nicholas67a0a8a2021-01-13 12:36:02 -0500237 int oldErrorCount = fErrors->errorCount();
John Stilesdce4d3e2020-09-25 14:35:13 -0400238 this->visitExpression(expr);
John Stilesb21fac22020-12-04 15:36:49 -0500239 if (info) {
240 info->fAssignedVar = fAssignedVar;
John Stilesb21fac22020-12-04 15:36:49 -0500241 }
Ethan Nicholas67a0a8a2021-01-13 12:36:02 -0500242 return fErrors->errorCount() == oldErrorCount;
John Stilesdce4d3e2020-09-25 14:35:13 -0400243 }
244
245 void visitExpression(Expression& expr) {
246 switch (expr.kind()) {
247 case Expression::Kind::kVariableReference: {
248 VariableReference& varRef = expr.as<VariableReference>();
Ethan Nicholas78686922020-10-08 06:46:27 -0400249 const Variable* var = varRef.variable();
Brian Osmane49703f2021-04-19 11:15:24 -0400250 if (var->modifiers().fFlags & (Modifiers::kConst_Flag | Modifiers::kUniform_Flag)) {
Ethan Nicholas89cfde12021-09-27 11:20:34 -0400251 fErrors->error(expr.fLine,
Ethan Nicholase2c49992020-10-05 11:49:11 -0400252 "cannot modify immutable variable '" + var->name() + "'");
John Stilesb21fac22020-12-04 15:36:49 -0500253 } else {
254 SkASSERT(fAssignedVar == nullptr);
255 fAssignedVar = &varRef;
John Stilesdce4d3e2020-09-25 14:35:13 -0400256 }
257 break;
258 }
259 case Expression::Kind::kFieldAccess:
Ethan Nicholas7a95b202020-10-09 11:55:40 -0400260 this->visitExpression(*expr.as<FieldAccess>().base());
John Stilesdce4d3e2020-09-25 14:35:13 -0400261 break;
262
263 case Expression::Kind::kSwizzle: {
264 const Swizzle& swizzle = expr.as<Swizzle>();
265 this->checkSwizzleWrite(swizzle);
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400266 this->visitExpression(*swizzle.base());
John Stilesdce4d3e2020-09-25 14:35:13 -0400267 break;
268 }
John Stiles47c0a742021-02-09 09:30:35 -0500269 case Expression::Kind::kIndex:
270 this->visitExpression(*expr.as<IndexExpression>().base());
John Stilesdce4d3e2020-09-25 14:35:13 -0400271 break;
John Stiles47c0a742021-02-09 09:30:35 -0500272
Ethan Nicholasc898d042021-08-28 19:53:34 -0400273 case Expression::Kind::kPoison:
274 break;
275
John Stilesdce4d3e2020-09-25 14:35:13 -0400276 default:
Ethan Nicholas89cfde12021-09-27 11:20:34 -0400277 fErrors->error(expr.fLine, "cannot assign to this expression");
John Stilesdce4d3e2020-09-25 14:35:13 -0400278 break;
279 }
280 }
281
282private:
283 void checkSwizzleWrite(const Swizzle& swizzle) {
284 int bits = 0;
John Stiles6e88e042021-02-19 14:09:38 -0500285 for (int8_t idx : swizzle.components()) {
286 SkASSERT(idx >= SwizzleComponent::X && idx <= SwizzleComponent::W);
John Stilesdce4d3e2020-09-25 14:35:13 -0400287 int bit = 1 << idx;
288 if (bits & bit) {
Ethan Nicholas89cfde12021-09-27 11:20:34 -0400289 fErrors->error(swizzle.fLine,
John Stilesa976da72020-09-25 23:06:26 -0400290 "cannot write to the same swizzle field more than once");
John Stilesdce4d3e2020-09-25 14:35:13 -0400291 break;
292 }
293 bits |= bit;
294 }
295 }
296
John Stilesa976da72020-09-25 23:06:26 -0400297 ErrorReporter* fErrors;
John Stilesb21fac22020-12-04 15:36:49 -0500298 VariableReference* fAssignedVar = nullptr;
John Stilesdce4d3e2020-09-25 14:35:13 -0400299
300 using INHERITED = ProgramVisitor;
301};
302
John Stilesa6841be2020-08-06 14:11:56 -0400303} // namespace
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400304
305////////////////////////////////////////////////////////////////////////////////
306// Analysis
307
Brian Osman4d571112021-04-27 09:10:10 -0400308SampleUsage Analysis::GetSampleUsage(const Program& program,
Brian Osman293497e2021-08-24 14:08:50 -0400309 const Variable& child,
Brian Osman8cdf28f2021-05-24 09:52:39 -0400310 bool writesToSampleCoords,
311 int* elidedSampleCoordCount) {
Brian Osman293497e2021-08-24 14:08:50 -0400312 MergeSampleUsageVisitor visitor(*program.fContext, child, writesToSampleCoords);
Brian Osman8cdf28f2021-05-24 09:52:39 -0400313 SampleUsage result = visitor.visit(program);
314 if (elidedSampleCoordCount) {
315 *elidedSampleCoordCount += visitor.elidedSampleCoordCount();
316 }
317 return result;
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400318}
319
Brian Osman92aac1e2020-08-05 16:48:58 -0400320bool Analysis::ReferencesBuiltin(const Program& program, int builtin) {
321 BuiltinVariableVisitor visitor(builtin);
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400322 return visitor.visit(program);
323}
324
Brian Osman92aac1e2020-08-05 16:48:58 -0400325bool Analysis::ReferencesSampleCoords(const Program& program) {
326 return Analysis::ReferencesBuiltin(program, SK_MAIN_COORDS_BUILTIN);
327}
328
329bool Analysis::ReferencesFragCoords(const Program& program) {
330 return Analysis::ReferencesBuiltin(program, SK_FRAGCOORD_BUILTIN);
331}
332
Brian Osman04d79fc2021-07-02 13:25:35 -0400333bool Analysis::CallsSampleOutsideMain(const Program& program) {
334 SampleOutsideMainVisitor visitor;
335 return visitor.visit(program);
336}
337
Ethan Nicholas98eae1e2021-09-01 14:37:29 -0400338bool Analysis::DetectVarDeclarationWithoutScope(const Statement& stmt, ErrorReporter* errors) {
339 // A variable declaration can create either a lone VarDeclaration or an unscoped Block
340 // containing multiple VarDeclaration statements. We need to detect either case.
341 const Variable* var;
342 if (stmt.is<VarDeclaration>()) {
343 // The single-variable case. No blocks at all.
344 var = &stmt.as<VarDeclaration>().var();
345 } else if (stmt.is<Block>()) {
346 // The multiple-variable case: an unscoped, non-empty block...
347 const Block& block = stmt.as<Block>();
348 if (block.isScope() || block.children().empty()) {
349 return false;
350 }
351 // ... holding a variable declaration.
352 const Statement& innerStmt = *block.children().front();
353 if (!innerStmt.is<VarDeclaration>()) {
354 return false;
355 }
356 var = &innerStmt.as<VarDeclaration>().var();
357 } else {
358 // This statement wasn't a variable declaration. No problem.
359 return false;
360 }
361
362 // Report an error.
363 SkASSERT(var);
364 if (errors) {
Ethan Nicholas89cfde12021-09-27 11:20:34 -0400365 errors->error(stmt.fLine, "variable '" + var->name() + "' must be created in a scope");
Ethan Nicholas98eae1e2021-09-01 14:37:29 -0400366 }
367 return true;
368}
369
John Stiles9b9415e2020-11-23 14:48:06 -0500370int Analysis::NodeCountUpToLimit(const FunctionDefinition& function, int limit) {
371 return NodeCountVisitor{limit}.visit(*function.body());
Ethan Nicholas6e0fa402020-08-20 14:08:23 -0400372}
373
Ethan Nicholas765d2fe2020-08-26 08:29:55 -0400374bool Analysis::StatementWritesToVariable(const Statement& stmt, const Variable& var) {
375 return VariableWriteVisitor(&var).visit(stmt);
376}
377
John Stilesb21fac22020-12-04 15:36:49 -0500378bool Analysis::IsAssignable(Expression& expr, AssignmentInfo* info, ErrorReporter* errors) {
John Stilesa976da72020-09-25 23:06:26 -0400379 TrivialErrorReporter trivialErrors;
John Stilesb21fac22020-12-04 15:36:49 -0500380 return IsAssignableVisitor{errors ? errors : &trivialErrors}.visit(expr, info);
John Stilesdce4d3e2020-09-25 14:35:13 -0400381}
382
John Stilesbb8cf582021-08-26 23:34:59 -0400383bool Analysis::UpdateVariableRefKind(Expression* expr,
384 VariableReference::RefKind kind,
385 ErrorReporter* errors) {
John Stiles516704b2021-02-26 15:01:57 -0500386 Analysis::AssignmentInfo info;
387 if (!Analysis::IsAssignable(*expr, &info, errors)) {
388 return false;
389 }
390 if (!info.fAssignedVar) {
John Stilesbb8cf582021-08-26 23:34:59 -0400391 if (errors) {
Ethan Nicholas89cfde12021-09-27 11:20:34 -0400392 errors->error(expr->fLine, "can't assign to expression '" + expr->description() + "'");
John Stilesbb8cf582021-08-26 23:34:59 -0400393 }
John Stiles516704b2021-02-26 15:01:57 -0500394 return false;
395 }
396 info.fAssignedVar->setRefKind(kind);
397 return true;
398}
399
John Stilesc30fbca2020-11-19 16:25:49 -0500400bool Analysis::IsTrivialExpression(const Expression& expr) {
John Stiles7591d4b2021-09-13 13:32:06 -0400401 return expr.is<Literal>() ||
John Stilesc30fbca2020-11-19 16:25:49 -0500402 expr.is<VariableReference>() ||
403 (expr.is<Swizzle>() &&
404 IsTrivialExpression(*expr.as<Swizzle>().base())) ||
405 (expr.is<FieldAccess>() &&
406 IsTrivialExpression(*expr.as<FieldAccess>().base())) ||
John Stiles2938eea2021-04-01 18:58:25 -0400407 (expr.isAnyConstructor() &&
408 expr.asAnyConstructor().argumentSpan().size() == 1 &&
409 IsTrivialExpression(*expr.asAnyConstructor().argumentSpan().front())) ||
410 (expr.isAnyConstructor() &&
John Stilesc30fbca2020-11-19 16:25:49 -0500411 expr.isConstantOrUniform()) ||
412 (expr.is<IndexExpression>() &&
John Stiles7591d4b2021-09-13 13:32:06 -0400413 expr.as<IndexExpression>().index()->isIntLiteral() &&
John Stilesc30fbca2020-11-19 16:25:49 -0500414 IsTrivialExpression(*expr.as<IndexExpression>().base()));
415}
416
John Stiles5676c572021-03-08 17:10:52 -0500417bool Analysis::IsSameExpressionTree(const Expression& left, const Expression& right) {
John Stiles95d0bad2021-03-01 17:02:28 -0500418 if (left.kind() != right.kind() || left.type() != right.type()) {
419 return false;
420 }
421
John Stiles5676c572021-03-08 17:10:52 -0500422 // This isn't a fully exhaustive list of expressions by any stretch of the imagination; for
423 // instance, `x[y+1] = x[y+1]` isn't detected because we don't look at BinaryExpressions.
424 // Since this is intended to be used for optimization purposes, handling the common cases is
425 // sufficient.
John Stiles95d0bad2021-03-01 17:02:28 -0500426 switch (left.kind()) {
John Stiles7591d4b2021-09-13 13:32:06 -0400427 case Expression::Kind::kLiteral:
428 return left.as<Literal>().value() == right.as<Literal>().value();
John Stiles5676c572021-03-08 17:10:52 -0500429
John Stiles7384b372021-04-01 13:48:15 -0400430 case Expression::Kind::kConstructorArray:
John Stilese3ae9682021-08-05 10:35:01 -0400431 case Expression::Kind::kConstructorArrayCast:
John Stiles8cad6372021-04-07 12:31:13 -0400432 case Expression::Kind::kConstructorCompound:
433 case Expression::Kind::kConstructorCompoundCast:
John Stiles2938eea2021-04-01 18:58:25 -0400434 case Expression::Kind::kConstructorDiagonalMatrix:
John Stiles5abb9e12021-04-06 13:47:19 -0400435 case Expression::Kind::kConstructorMatrixResize:
John Stilesfd7252f2021-04-04 22:24:40 -0400436 case Expression::Kind::kConstructorScalarCast:
John Stilesd47330f2021-04-08 23:25:52 -0400437 case Expression::Kind::kConstructorStruct:
John Stiles268a73f2021-04-07 12:30:22 -0400438 case Expression::Kind::kConstructorSplat: {
John Stilesfd7252f2021-04-04 22:24:40 -0400439 if (left.kind() != right.kind()) {
440 return false;
441 }
John Stiles7384b372021-04-01 13:48:15 -0400442 const AnyConstructor& leftCtor = left.asAnyConstructor();
443 const AnyConstructor& rightCtor = right.asAnyConstructor();
444 const auto leftSpan = leftCtor.argumentSpan();
445 const auto rightSpan = rightCtor.argumentSpan();
446 if (leftSpan.size() != rightSpan.size()) {
John Stiles5676c572021-03-08 17:10:52 -0500447 return false;
448 }
John Stiles7384b372021-04-01 13:48:15 -0400449 for (size_t index = 0; index < leftSpan.size(); ++index) {
450 if (!IsSameExpressionTree(*leftSpan[index], *rightSpan[index])) {
John Stiles5676c572021-03-08 17:10:52 -0500451 return false;
452 }
453 }
454 return true;
455 }
John Stiles95d0bad2021-03-01 17:02:28 -0500456 case Expression::Kind::kFieldAccess:
457 return left.as<FieldAccess>().fieldIndex() == right.as<FieldAccess>().fieldIndex() &&
John Stiles5676c572021-03-08 17:10:52 -0500458 IsSameExpressionTree(*left.as<FieldAccess>().base(),
459 *right.as<FieldAccess>().base());
John Stiles95d0bad2021-03-01 17:02:28 -0500460
461 case Expression::Kind::kIndex:
John Stiles5676c572021-03-08 17:10:52 -0500462 return IsSameExpressionTree(*left.as<IndexExpression>().index(),
463 *right.as<IndexExpression>().index()) &&
464 IsSameExpressionTree(*left.as<IndexExpression>().base(),
465 *right.as<IndexExpression>().base());
John Stiles95d0bad2021-03-01 17:02:28 -0500466
467 case Expression::Kind::kSwizzle:
468 return left.as<Swizzle>().components() == right.as<Swizzle>().components() &&
John Stiles5676c572021-03-08 17:10:52 -0500469 IsSameExpressionTree(*left.as<Swizzle>().base(), *right.as<Swizzle>().base());
John Stiles95d0bad2021-03-01 17:02:28 -0500470
471 case Expression::Kind::kVariableReference:
472 return left.as<VariableReference>().variable() ==
473 right.as<VariableReference>().variable();
474
475 default:
476 return false;
477 }
478}
479
Brian Osman7b361492021-02-25 11:25:30 -0500480// Checks for ES2 constant-expression rules, and (optionally) constant-index-expression rules
481// (if loopIndices is non-nullptr)
482class ConstantExpressionVisitor : public ProgramVisitor {
Brian Osmanea485e52021-01-15 13:20:32 -0500483public:
Brian Osman7b361492021-02-25 11:25:30 -0500484 ConstantExpressionVisitor(const std::set<const Variable*>* loopIndices)
Brian Osmanea485e52021-01-15 13:20:32 -0500485 : fLoopIndices(loopIndices) {}
486
487 bool visitExpression(const Expression& e) override {
488 // A constant-(index)-expression is one of...
489 switch (e.kind()) {
490 // ... a literal value
John Stiles7591d4b2021-09-13 13:32:06 -0400491 case Expression::Kind::kLiteral:
Brian Osmanea485e52021-01-15 13:20:32 -0500492 return false;
493
John Stiles532138c2021-03-04 16:29:22 -0500494 // ... settings can appear in fragment processors; they will resolve when compiled
495 case Expression::Kind::kSetting:
496 return false;
497
Brian Osman7b361492021-02-25 11:25:30 -0500498 // ... a global or local variable qualified as 'const', excluding function parameters.
499 // ... loop indices as defined in section 4. [constant-index-expression]
500 case Expression::Kind::kVariableReference: {
501 const Variable* v = e.as<VariableReference>().variable();
502 if ((v->storage() == Variable::Storage::kGlobal ||
503 v->storage() == Variable::Storage::kLocal) &&
504 (v->modifiers().fFlags & Modifiers::kConst_Flag)) {
505 return false;
506 }
507 return !fLoopIndices || fLoopIndices->find(v) == fLoopIndices->end();
508 }
Brian Osmanea485e52021-01-15 13:20:32 -0500509
510 // ... expressions composed of both of the above
511 case Expression::Kind::kBinary:
John Stiles7384b372021-04-01 13:48:15 -0400512 case Expression::Kind::kConstructorArray:
John Stilese3ae9682021-08-05 10:35:01 -0400513 case Expression::Kind::kConstructorArrayCast:
John Stiles8cad6372021-04-07 12:31:13 -0400514 case Expression::Kind::kConstructorCompound:
515 case Expression::Kind::kConstructorCompoundCast:
John Stilese1182782021-03-30 22:09:37 -0400516 case Expression::Kind::kConstructorDiagonalMatrix:
John Stiles5abb9e12021-04-06 13:47:19 -0400517 case Expression::Kind::kConstructorMatrixResize:
John Stilesfd7252f2021-04-04 22:24:40 -0400518 case Expression::Kind::kConstructorScalarCast:
John Stiles2938eea2021-04-01 18:58:25 -0400519 case Expression::Kind::kConstructorSplat:
John Stilesd47330f2021-04-08 23:25:52 -0400520 case Expression::Kind::kConstructorStruct:
Brian Osmanea485e52021-01-15 13:20:32 -0500521 case Expression::Kind::kFieldAccess:
522 case Expression::Kind::kIndex:
523 case Expression::Kind::kPrefix:
524 case Expression::Kind::kPostfix:
525 case Expression::Kind::kSwizzle:
526 case Expression::Kind::kTernary:
527 return INHERITED::visitExpression(e);
528
John Stiles7bd3f1c2021-08-27 16:12:10 -0400529 // Function calls are completely disallowed in SkSL constant-(index)-expressions.
530 // GLSL does mandate that calling a built-in function where the arguments are all
531 // constant-expressions should result in a constant-expression. SkSL handles this by
532 // optimizing fully-constant function calls into literals in FunctionCall::Make.
Brian Osmanea485e52021-01-15 13:20:32 -0500533 case Expression::Kind::kFunctionCall:
John Stiles7bd3f1c2021-08-27 16:12:10 -0400534 case Expression::Kind::kExternalFunctionCall:
535 case Expression::Kind::kChildCall:
Brian Osmanea485e52021-01-15 13:20:32 -0500536
John Stiles7bd3f1c2021-08-27 16:12:10 -0400537 // These shouldn't appear in a valid program at all, and definitely aren't
538 // constant-index-expressions.
Ethan Nicholas549c6b82021-06-25 12:31:44 -0400539 case Expression::Kind::kPoison:
John Stiles7bd3f1c2021-08-27 16:12:10 -0400540 case Expression::Kind::kFunctionReference:
541 case Expression::Kind::kExternalFunctionReference:
Brian Osman3099f792021-09-01 13:12:16 -0400542 case Expression::Kind::kMethodReference:
John Stiles7bd3f1c2021-08-27 16:12:10 -0400543 case Expression::Kind::kTypeReference:
544 case Expression::Kind::kCodeString:
Ethan Nicholas549c6b82021-06-25 12:31:44 -0400545 return true;
546
Brian Osmanea485e52021-01-15 13:20:32 -0500547 default:
548 SkDEBUGFAIL("Unexpected expression type");
549 return true;
550 }
551 }
552
553private:
554 const std::set<const Variable*>* fLoopIndices;
555 using INHERITED = ProgramVisitor;
556};
557
558class ES2IndexingVisitor : public ProgramVisitor {
559public:
560 ES2IndexingVisitor(ErrorReporter& errors) : fErrors(errors) {}
561
562 bool visitStatement(const Statement& s) override {
563 if (s.is<ForStatement>()) {
564 const ForStatement& f = s.as<ForStatement>();
565 SkASSERT(f.initializer() && f.initializer()->is<VarDeclaration>());
566 const Variable* var = &f.initializer()->as<VarDeclaration>().var();
567 auto [iter, inserted] = fLoopIndices.insert(var);
568 SkASSERT(inserted);
569 bool result = this->visitStatement(*f.statement());
570 fLoopIndices.erase(iter);
571 return result;
572 }
573 return INHERITED::visitStatement(s);
574 }
575
576 bool visitExpression(const Expression& e) override {
577 if (e.is<IndexExpression>()) {
578 const IndexExpression& i = e.as<IndexExpression>();
Brian Osman7b361492021-02-25 11:25:30 -0500579 ConstantExpressionVisitor indexerInvalid(&fLoopIndices);
Brian Osmanea485e52021-01-15 13:20:32 -0500580 if (indexerInvalid.visitExpression(*i.index())) {
Ethan Nicholas89cfde12021-09-27 11:20:34 -0400581 fErrors.error(i.fLine, "index expression must be constant");
Brian Osmanea485e52021-01-15 13:20:32 -0500582 return true;
583 }
584 }
585 return INHERITED::visitExpression(e);
586 }
587
588 using ProgramVisitor::visitProgramElement;
589
590private:
591 ErrorReporter& fErrors;
592 std::set<const Variable*> fLoopIndices;
593 using INHERITED = ProgramVisitor;
594};
595
596
597void Analysis::ValidateIndexingForES2(const ProgramElement& pe, ErrorReporter& errors) {
598 ES2IndexingVisitor visitor(errors);
599 visitor.visitProgramElement(pe);
600}
601
Brian Osman7b361492021-02-25 11:25:30 -0500602bool Analysis::IsConstantExpression(const Expression& expr) {
603 ConstantExpressionVisitor visitor(/*loopIndices=*/nullptr);
604 return !visitor.visitExpression(expr);
605}
606
John Stiles2ecc5952021-09-01 14:41:36 -0400607void Analysis::VerifyStaticTestsAndExpressions(const Program& program) {
608 class TestsAndExpressions : public ProgramVisitor {
John Stiles0fc6bed2021-09-01 11:35:59 -0400609 public:
John Stiles2ecc5952021-09-01 14:41:36 -0400610 TestsAndExpressions(const Context& ctx) : fContext(ctx) {}
John Stiles0fc6bed2021-09-01 11:35:59 -0400611
612 using ProgramVisitor::visitProgramElement;
613
614 bool visitStatement(const Statement& stmt) override {
John Stiles2ecc5952021-09-01 14:41:36 -0400615 if (!fContext.fConfig->fSettings.fPermitInvalidStaticTests) {
616 switch (stmt.kind()) {
617 case Statement::Kind::kIf:
618 if (stmt.as<IfStatement>().isStatic()) {
Ethan Nicholas89cfde12021-09-27 11:20:34 -0400619 fContext.fErrors->error(stmt.fLine, "static if has non-static test");
John Stiles2ecc5952021-09-01 14:41:36 -0400620 }
621 break;
John Stiles0fc6bed2021-09-01 11:35:59 -0400622
John Stiles2ecc5952021-09-01 14:41:36 -0400623 case Statement::Kind::kSwitch:
624 if (stmt.as<SwitchStatement>().isStatic()) {
Ethan Nicholas89cfde12021-09-27 11:20:34 -0400625 fContext.fErrors->error(stmt.fLine,
John Stiles2ecc5952021-09-01 14:41:36 -0400626 "static switch has non-static test");
627 }
628 break;
John Stiles0fc6bed2021-09-01 11:35:59 -0400629
John Stiles2ecc5952021-09-01 14:41:36 -0400630 default:
631 break;
632 }
John Stiles0fc6bed2021-09-01 11:35:59 -0400633 }
634 return INHERITED::visitStatement(stmt);
635 }
636
John Stiles2ecc5952021-09-01 14:41:36 -0400637 bool visitExpression(const Expression& expr) override {
638 switch (expr.kind()) {
639 case Expression::Kind::kFunctionCall: {
640 const FunctionDeclaration& decl = expr.as<FunctionCall>().function();
641 if (!decl.isBuiltin() && !decl.definition()) {
Ethan Nicholas89cfde12021-09-27 11:20:34 -0400642 fContext.fErrors->error(expr.fLine, "function '" + decl.description() +
643 "' is not defined");
John Stiles2ecc5952021-09-01 14:41:36 -0400644 }
645 break;
646 }
647 case Expression::Kind::kExternalFunctionReference:
648 case Expression::Kind::kFunctionReference:
Brian Osman3099f792021-09-01 13:12:16 -0400649 case Expression::Kind::kMethodReference:
John Stiles2ecc5952021-09-01 14:41:36 -0400650 case Expression::Kind::kTypeReference:
651 SkDEBUGFAIL("invalid reference-expr, should have been reported by coerce()");
Ethan Nicholas89cfde12021-09-27 11:20:34 -0400652 fContext.fErrors->error(expr.fLine, "invalid expression");
John Stiles2ecc5952021-09-01 14:41:36 -0400653 break;
654 default:
655 if (expr.type() == *fContext.fTypes.fInvalid) {
Ethan Nicholas89cfde12021-09-27 11:20:34 -0400656 fContext.fErrors->error(expr.fLine, "invalid expression");
John Stiles2ecc5952021-09-01 14:41:36 -0400657 }
658 break;
659 }
660 return INHERITED::visitExpression(expr);
John Stiles0fc6bed2021-09-01 11:35:59 -0400661 }
662
663 private:
664 using INHERITED = ProgramVisitor;
John Stiles2ecc5952021-09-01 14:41:36 -0400665 const Context& fContext;
John Stiles0fc6bed2021-09-01 11:35:59 -0400666 };
667
John Stiles0fc6bed2021-09-01 11:35:59 -0400668 // Check all of the program's owned elements. (Built-in elements are assumed to be valid.)
John Stiles2ecc5952021-09-01 14:41:36 -0400669 TestsAndExpressions visitor{*program.fContext};
John Stiles0fc6bed2021-09-01 11:35:59 -0400670 for (const std::unique_ptr<ProgramElement>& element : program.ownedElements()) {
John Stiles2ecc5952021-09-01 14:41:36 -0400671 visitor.visitProgramElement(*element);
John Stiles0fc6bed2021-09-01 11:35:59 -0400672 }
673}
674
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400675////////////////////////////////////////////////////////////////////////////////
676// ProgramVisitor
677
Brian Osman133724c2020-10-28 14:14:39 -0400678bool ProgramVisitor::visit(const Program& program) {
679 for (const ProgramElement* pe : program.elements()) {
Brian Osman1179fcf2020-10-08 16:04:40 -0400680 if (this->visitProgramElement(*pe)) {
John Stiles933abe32020-08-28 11:58:40 -0400681 return true;
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400682 }
683 }
John Stiles933abe32020-08-28 11:58:40 -0400684 return false;
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400685}
686
John Stiles48b25582021-03-11 14:26:42 -0500687template <typename T> bool TProgramVisitor<T>::visitExpression(typename T::Expression& e) {
John Stiles70b82422020-09-30 10:55:12 -0400688 switch (e.kind()) {
John Stiles6d023462021-10-06 12:51:10 -0400689 case Expression::Kind::kCodeString:
Brian Osmanbe0b3b72021-01-06 14:27:35 -0500690 case Expression::Kind::kExternalFunctionReference:
Ethan Nicholase6592142020-09-08 10:22:09 -0400691 case Expression::Kind::kFunctionReference:
John Stiles7591d4b2021-09-13 13:32:06 -0400692 case Expression::Kind::kLiteral:
Brian Osman3099f792021-09-01 13:12:16 -0400693 case Expression::Kind::kMethodReference:
Ethan Nicholas549c6b82021-06-25 12:31:44 -0400694 case Expression::Kind::kPoison:
Ethan Nicholase6592142020-09-08 10:22:09 -0400695 case Expression::Kind::kSetting:
696 case Expression::Kind::kTypeReference:
697 case Expression::Kind::kVariableReference:
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400698 // Leaf expressions return false
699 return false;
John Stiles70b82422020-09-30 10:55:12 -0400700
Ethan Nicholase6592142020-09-08 10:22:09 -0400701 case Expression::Kind::kBinary: {
John Stiles70b82422020-09-30 10:55:12 -0400702 auto& b = e.template as<BinaryExpression>();
John Stiles48b25582021-03-11 14:26:42 -0500703 return (b.left() && this->visitExpressionPtr(b.left())) ||
704 (b.right() && this->visitExpressionPtr(b.right()));
John Stiles70b82422020-09-30 10:55:12 -0400705 }
Brian Osmaneb0f29d2021-08-04 11:34:16 -0400706 case Expression::Kind::kChildCall: {
707 // We don't visit the child variable itself, just the arguments
708 auto& c = e.template as<ChildCall>();
709 for (auto& arg : c.arguments()) {
710 if (arg && this->visitExpressionPtr(arg)) { return true; }
711 }
712 return false;
713 }
John Stiles7384b372021-04-01 13:48:15 -0400714 case Expression::Kind::kConstructorArray:
John Stilese3ae9682021-08-05 10:35:01 -0400715 case Expression::Kind::kConstructorArrayCast:
John Stiles8cad6372021-04-07 12:31:13 -0400716 case Expression::Kind::kConstructorCompound:
717 case Expression::Kind::kConstructorCompoundCast:
John Stiles2938eea2021-04-01 18:58:25 -0400718 case Expression::Kind::kConstructorDiagonalMatrix:
John Stiles5abb9e12021-04-06 13:47:19 -0400719 case Expression::Kind::kConstructorMatrixResize:
John Stilesfd7252f2021-04-04 22:24:40 -0400720 case Expression::Kind::kConstructorScalarCast:
John Stilesd47330f2021-04-08 23:25:52 -0400721 case Expression::Kind::kConstructorSplat:
722 case Expression::Kind::kConstructorStruct: {
John Stiles7384b372021-04-01 13:48:15 -0400723 auto& c = e.asAnyConstructor();
724 for (auto& arg : c.argumentSpan()) {
John Stiles48b25582021-03-11 14:26:42 -0500725 if (this->visitExpressionPtr(arg)) { return true; }
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400726 }
John Stiles70b82422020-09-30 10:55:12 -0400727 return false;
728 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400729 case Expression::Kind::kExternalFunctionCall: {
John Stiles70b82422020-09-30 10:55:12 -0400730 auto& c = e.template as<ExternalFunctionCall>();
Ethan Nicholas6e86ec92020-09-30 14:29:56 -0400731 for (auto& arg : c.arguments()) {
John Stiles48b25582021-03-11 14:26:42 -0500732 if (this->visitExpressionPtr(arg)) { return true; }
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400733 }
John Stiles70b82422020-09-30 10:55:12 -0400734 return false;
735 }
John Stilesd7ab4502020-09-24 22:41:00 -0400736 case Expression::Kind::kFieldAccess:
John Stiles48b25582021-03-11 14:26:42 -0500737 return this->visitExpressionPtr(e.template as<FieldAccess>().base());
John Stiles70b82422020-09-30 10:55:12 -0400738
Ethan Nicholase6592142020-09-08 10:22:09 -0400739 case Expression::Kind::kFunctionCall: {
John Stiles70b82422020-09-30 10:55:12 -0400740 auto& c = e.template as<FunctionCall>();
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400741 for (auto& arg : c.arguments()) {
John Stiles48b25582021-03-11 14:26:42 -0500742 if (arg && this->visitExpressionPtr(arg)) { return true; }
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400743 }
John Stiles70b82422020-09-30 10:55:12 -0400744 return false;
745 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400746 case Expression::Kind::kIndex: {
John Stiles70b82422020-09-30 10:55:12 -0400747 auto& i = e.template as<IndexExpression>();
John Stiles48b25582021-03-11 14:26:42 -0500748 return this->visitExpressionPtr(i.base()) || this->visitExpressionPtr(i.index());
John Stiles70b82422020-09-30 10:55:12 -0400749 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400750 case Expression::Kind::kPostfix:
John Stiles48b25582021-03-11 14:26:42 -0500751 return this->visitExpressionPtr(e.template as<PostfixExpression>().operand());
John Stiles70b82422020-09-30 10:55:12 -0400752
Ethan Nicholase6592142020-09-08 10:22:09 -0400753 case Expression::Kind::kPrefix:
John Stiles48b25582021-03-11 14:26:42 -0500754 return this->visitExpressionPtr(e.template as<PrefixExpression>().operand());
John Stiles70b82422020-09-30 10:55:12 -0400755
Brian Osman010ce6a2020-10-19 16:34:10 -0400756 case Expression::Kind::kSwizzle: {
757 auto& s = e.template as<Swizzle>();
John Stiles48b25582021-03-11 14:26:42 -0500758 return s.base() && this->visitExpressionPtr(s.base());
Brian Osman010ce6a2020-10-19 16:34:10 -0400759 }
John Stiles70b82422020-09-30 10:55:12 -0400760
Ethan Nicholase6592142020-09-08 10:22:09 -0400761 case Expression::Kind::kTernary: {
John Stiles70b82422020-09-30 10:55:12 -0400762 auto& t = e.template as<TernaryExpression>();
John Stiles48b25582021-03-11 14:26:42 -0500763 return this->visitExpressionPtr(t.test()) ||
764 (t.ifTrue() && this->visitExpressionPtr(t.ifTrue())) ||
765 (t.ifFalse() && this->visitExpressionPtr(t.ifFalse()));
John Stiles70b82422020-09-30 10:55:12 -0400766 }
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400767 default:
768 SkUNREACHABLE;
769 }
770}
771
John Stiles48b25582021-03-11 14:26:42 -0500772template <typename T> bool TProgramVisitor<T>::visitStatement(typename T::Statement& s) {
John Stiles70b82422020-09-30 10:55:12 -0400773 switch (s.kind()) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400774 case Statement::Kind::kBreak:
775 case Statement::Kind::kContinue:
776 case Statement::Kind::kDiscard:
John Stiles98c1f822020-09-09 14:18:53 -0400777 case Statement::Kind::kInlineMarker:
Ethan Nicholase6592142020-09-08 10:22:09 -0400778 case Statement::Kind::kNop:
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400779 // Leaf statements just return false
780 return false;
John Stiles70b82422020-09-30 10:55:12 -0400781
Ethan Nicholase6592142020-09-08 10:22:09 -0400782 case Statement::Kind::kBlock:
John Stiles70b82422020-09-30 10:55:12 -0400783 for (auto& stmt : s.template as<Block>().children()) {
John Stiles48b25582021-03-11 14:26:42 -0500784 if (stmt && this->visitStatementPtr(stmt)) {
Ethan Nicholas7bd60432020-09-25 14:31:59 -0400785 return true;
786 }
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400787 }
788 return false;
John Stiles70b82422020-09-30 10:55:12 -0400789
John Stilesa0e56e32021-03-03 13:14:37 -0500790 case Statement::Kind::kSwitchCase: {
791 auto& sc = s.template as<SwitchCase>();
John Stiles48b25582021-03-11 14:26:42 -0500792 if (sc.value() && this->visitExpressionPtr(sc.value())) {
John Stilesa0e56e32021-03-03 13:14:37 -0500793 return true;
794 }
John Stiles48b25582021-03-11 14:26:42 -0500795 return this->visitStatementPtr(sc.statement());
John Stilesa0e56e32021-03-03 13:14:37 -0500796 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400797 case Statement::Kind::kDo: {
John Stiles70b82422020-09-30 10:55:12 -0400798 auto& d = s.template as<DoStatement>();
John Stiles48b25582021-03-11 14:26:42 -0500799 return this->visitExpressionPtr(d.test()) || this->visitStatementPtr(d.statement());
John Stiles70b82422020-09-30 10:55:12 -0400800 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400801 case Statement::Kind::kExpression:
John Stiles48b25582021-03-11 14:26:42 -0500802 return this->visitExpressionPtr(s.template as<ExpressionStatement>().expression());
John Stiles70b82422020-09-30 10:55:12 -0400803
Ethan Nicholase6592142020-09-08 10:22:09 -0400804 case Statement::Kind::kFor: {
John Stiles70b82422020-09-30 10:55:12 -0400805 auto& f = s.template as<ForStatement>();
John Stiles48b25582021-03-11 14:26:42 -0500806 return (f.initializer() && this->visitStatementPtr(f.initializer())) ||
807 (f.test() && this->visitExpressionPtr(f.test())) ||
808 (f.next() && this->visitExpressionPtr(f.next())) ||
809 this->visitStatementPtr(f.statement());
John Stiles70b82422020-09-30 10:55:12 -0400810 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400811 case Statement::Kind::kIf: {
John Stiles70b82422020-09-30 10:55:12 -0400812 auto& i = s.template as<IfStatement>();
John Stiles48b25582021-03-11 14:26:42 -0500813 return (i.test() && this->visitExpressionPtr(i.test())) ||
814 (i.ifTrue() && this->visitStatementPtr(i.ifTrue())) ||
815 (i.ifFalse() && this->visitStatementPtr(i.ifFalse()));
John Stiles70b82422020-09-30 10:55:12 -0400816 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400817 case Statement::Kind::kReturn: {
John Stiles70b82422020-09-30 10:55:12 -0400818 auto& r = s.template as<ReturnStatement>();
John Stiles48b25582021-03-11 14:26:42 -0500819 return r.expression() && this->visitExpressionPtr(r.expression());
John Stiles70b82422020-09-30 10:55:12 -0400820 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400821 case Statement::Kind::kSwitch: {
John Stiles70b82422020-09-30 10:55:12 -0400822 auto& sw = s.template as<SwitchStatement>();
John Stiles48b25582021-03-11 14:26:42 -0500823 if (this->visitExpressionPtr(sw.value())) {
John Stiles70b82422020-09-30 10:55:12 -0400824 return true;
825 }
John Stiles48b25582021-03-11 14:26:42 -0500826 for (auto& c : sw.cases()) {
827 if (this->visitStatementPtr(c)) {
John Stiles70b82422020-09-30 10:55:12 -0400828 return true;
829 }
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400830 }
John Stiles70b82422020-09-30 10:55:12 -0400831 return false;
832 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400833 case Statement::Kind::kVarDeclaration: {
John Stiles70b82422020-09-30 10:55:12 -0400834 auto& v = s.template as<VarDeclaration>();
John Stiles48b25582021-03-11 14:26:42 -0500835 return v.value() && this->visitExpressionPtr(v.value());
John Stiles70b82422020-09-30 10:55:12 -0400836 }
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400837 default:
838 SkUNREACHABLE;
839 }
840}
841
John Stiles48b25582021-03-11 14:26:42 -0500842template <typename T> bool TProgramVisitor<T>::visitProgramElement(typename T::ProgramElement& pe) {
John Stiles70b82422020-09-30 10:55:12 -0400843 switch (pe.kind()) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400844 case ProgramElement::Kind::kExtension:
John Stiles569249b2020-11-03 12:18:22 -0500845 case ProgramElement::Kind::kFunctionPrototype:
John Stilesd39aec02020-12-03 10:42:26 -0500846 case ProgramElement::Kind::kInterfaceBlock:
Ethan Nicholase6592142020-09-08 10:22:09 -0400847 case ProgramElement::Kind::kModifiers:
John Stilesdc75a972020-11-25 16:24:55 -0500848 case ProgramElement::Kind::kStructDefinition:
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400849 // Leaf program elements just return false by default
850 return false;
John Stiles70b82422020-09-30 10:55:12 -0400851
Ethan Nicholase6592142020-09-08 10:22:09 -0400852 case ProgramElement::Kind::kFunction:
John Stiles48b25582021-03-11 14:26:42 -0500853 return this->visitStatementPtr(pe.template as<FunctionDefinition>().body());
John Stiles70b82422020-09-30 10:55:12 -0400854
Brian Osmanc0213602020-10-06 14:43:32 -0400855 case ProgramElement::Kind::kGlobalVar:
John Stiles48b25582021-03-11 14:26:42 -0500856 return this->visitStatementPtr(pe.template as<GlobalVarDeclaration>().declaration());
John Stiles70b82422020-09-30 10:55:12 -0400857
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400858 default:
859 SkUNREACHABLE;
860 }
861}
862
John Stiles48b25582021-03-11 14:26:42 -0500863template class TProgramVisitor<ProgramVisitorTypes>;
864template class TProgramVisitor<ProgramWriterTypes>;
John Stiles70b82422020-09-30 10:55:12 -0400865
John Stilesa6841be2020-08-06 14:11:56 -0400866} // namespace SkSL