blob: 71bf93c22df8f5ddceaab08ea56e681d0e24d7f4 [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
Brian Osman1298bc42020-06-30 13:39:35 -040010#include "include/private/SkSLSampleUsage.h"
John Stilesdce4d3e2020-09-25 14:35:13 -040011#include "src/sksl/SkSLErrorReporter.h"
Michael Ludwig8f3a8362020-06-29 17:27:00 -040012#include "src/sksl/ir/SkSLExpression.h"
13#include "src/sksl/ir/SkSLProgram.h"
14#include "src/sksl/ir/SkSLProgramElement.h"
15#include "src/sksl/ir/SkSLStatement.h"
16
17// ProgramElements
18#include "src/sksl/ir/SkSLEnum.h"
19#include "src/sksl/ir/SkSLExtension.h"
20#include "src/sksl/ir/SkSLFunctionDefinition.h"
21#include "src/sksl/ir/SkSLInterfaceBlock.h"
22#include "src/sksl/ir/SkSLModifiers.h"
23#include "src/sksl/ir/SkSLSection.h"
24#include "src/sksl/ir/SkSLVarDeclarations.h"
25
26// Statements
27#include "src/sksl/ir/SkSLBlock.h"
28#include "src/sksl/ir/SkSLBreakStatement.h"
29#include "src/sksl/ir/SkSLContinueStatement.h"
30#include "src/sksl/ir/SkSLDiscardStatement.h"
31#include "src/sksl/ir/SkSLDoStatement.h"
32#include "src/sksl/ir/SkSLExpressionStatement.h"
33#include "src/sksl/ir/SkSLForStatement.h"
34#include "src/sksl/ir/SkSLIfStatement.h"
35#include "src/sksl/ir/SkSLNop.h"
36#include "src/sksl/ir/SkSLReturnStatement.h"
37#include "src/sksl/ir/SkSLSwitchStatement.h"
Michael Ludwig8f3a8362020-06-29 17:27:00 -040038#include "src/sksl/ir/SkSLWhileStatement.h"
39
40// Expressions
41#include "src/sksl/ir/SkSLBinaryExpression.h"
42#include "src/sksl/ir/SkSLBoolLiteral.h"
43#include "src/sksl/ir/SkSLConstructor.h"
44#include "src/sksl/ir/SkSLExternalFunctionCall.h"
45#include "src/sksl/ir/SkSLExternalValueReference.h"
46#include "src/sksl/ir/SkSLFieldAccess.h"
47#include "src/sksl/ir/SkSLFloatLiteral.h"
48#include "src/sksl/ir/SkSLFunctionCall.h"
49#include "src/sksl/ir/SkSLFunctionReference.h"
50#include "src/sksl/ir/SkSLIndexExpression.h"
John Stiles98c1f822020-09-09 14:18:53 -040051#include "src/sksl/ir/SkSLInlineMarker.h"
Michael Ludwig8f3a8362020-06-29 17:27:00 -040052#include "src/sksl/ir/SkSLIntLiteral.h"
53#include "src/sksl/ir/SkSLNullLiteral.h"
54#include "src/sksl/ir/SkSLPostfixExpression.h"
55#include "src/sksl/ir/SkSLPrefixExpression.h"
56#include "src/sksl/ir/SkSLSetting.h"
57#include "src/sksl/ir/SkSLSwizzle.h"
58#include "src/sksl/ir/SkSLTernaryExpression.h"
59#include "src/sksl/ir/SkSLTypeReference.h"
60#include "src/sksl/ir/SkSLVariableReference.h"
61
62namespace SkSL {
63
64namespace {
65
66static bool is_sample_call_to_fp(const FunctionCall& fc, const Variable& fp) {
Ethan Nicholas0dec9922020-10-05 15:51:52 -040067 const FunctionDeclaration& f = fc.function();
Ethan Nicholased84b732020-10-08 11:45:44 -040068 return f.isBuiltin() && f.name() == "sample" && fc.arguments().size() >= 1 &&
Ethan Nicholas0dec9922020-10-05 15:51:52 -040069 fc.arguments()[0]->is<VariableReference>() &&
Ethan Nicholas78686922020-10-08 06:46:27 -040070 fc.arguments()[0]->as<VariableReference>().variable() == &fp;
Michael Ludwig8f3a8362020-06-29 17:27:00 -040071}
72
Brian Osman1298bc42020-06-30 13:39:35 -040073// Visitor that determines the merged SampleUsage for a given child 'fp' in the program.
74class MergeSampleUsageVisitor : public ProgramVisitor {
Michael Ludwig8f3a8362020-06-29 17:27:00 -040075public:
John Stiles933abe32020-08-28 11:58:40 -040076 MergeSampleUsageVisitor(const Context& context, const Variable& fp)
77 : fContext(context), fFP(fp) {}
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
85protected:
John Stiles933abe32020-08-28 11:58:40 -040086 const Context& fContext;
Michael Ludwig8f3a8362020-06-29 17:27:00 -040087 const Variable& fFP;
Brian Osman1298bc42020-06-30 13:39:35 -040088 SampleUsage fUsage;
Michael Ludwig8f3a8362020-06-29 17:27:00 -040089
90 bool visitExpression(const Expression& e) override {
Brian Osman1298bc42020-06-30 13:39:35 -040091 // Looking for sample(fp, inColor?, ...)
Ethan Nicholase6592142020-09-08 10:22:09 -040092 if (e.kind() == Expression::Kind::kFunctionCall) {
John Stiles403a3632020-08-20 12:11:48 -040093 const FunctionCall& fc = e.as<FunctionCall>();
Brian Osman1298bc42020-06-30 13:39:35 -040094 if (is_sample_call_to_fp(fc, fFP)) {
95 // Determine the type of call at this site, and merge it with the accumulated state
Ethan Nicholas0dec9922020-10-05 15:51:52 -040096 const Expression* lastArg = fc.arguments().back().get();
Brian Osman1298bc42020-06-30 13:39:35 -040097
Ethan Nicholas30d30222020-09-11 12:27:26 -040098 if (lastArg->type() == *fContext.fFloat2_Type) {
Brian Osman1298bc42020-06-30 13:39:35 -040099 fUsage.merge(SampleUsage::Explicit());
Ethan Nicholas30d30222020-09-11 12:27:26 -0400100 } else if (lastArg->type() == *fContext.fFloat3x3_Type) {
Brian Osman1298bc42020-06-30 13:39:35 -0400101 // Determine the type of matrix for this call site
102 if (lastArg->isConstantOrUniform()) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400103 if (lastArg->kind() == Expression::Kind::kVariableReference ||
104 lastArg->kind() == Expression::Kind::kConstructor) {
Brian Osman1298bc42020-06-30 13:39:35 -0400105 // FIXME if this is a constant, we should parse the float3x3 constructor
106 // and determine if the resulting matrix introduces perspective.
107 fUsage.merge(SampleUsage::UniformMatrix(lastArg->description()));
108 } else {
109 // FIXME this is really to workaround a restriction of the downstream
110 // code that relies on the SampleUsage's fExpression to identify uniform
111 // names. Once they are tracked separately, any uniform expression can
112 // work, but right now this avoids issues from '0.5 * matrix' that is
113 // both a constant AND a uniform.
114 fUsage.merge(SampleUsage::VariableMatrix());
115 }
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400116 } else {
Brian Osman1298bc42020-06-30 13:39:35 -0400117 fUsage.merge(SampleUsage::VariableMatrix());
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400118 }
119 } else {
Brian Osman1298bc42020-06-30 13:39:35 -0400120 // The only other signatures do pass-through sampling
121 fUsage.merge(SampleUsage::PassThrough());
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400122 }
Brian Osman1298bc42020-06-30 13:39:35 -0400123 // NOTE: we don't return true here just because we found a sample call. We need to
124 // process the entire program and merge across all encountered calls.
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400125 }
126 }
127
John Stilesd7ab4502020-09-24 22:41:00 -0400128 return INHERITED::visitExpression(e);
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400129 }
130
John Stiles7571f9e2020-09-02 22:42:33 -0400131 using INHERITED = ProgramVisitor;
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400132};
133
Brian Osman92aac1e2020-08-05 16:48:58 -0400134// Visitor that searches through the program for references to a particular builtin variable
135class BuiltinVariableVisitor : public ProgramVisitor {
136public:
137 BuiltinVariableVisitor(int builtin) : fBuiltin(builtin) {}
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400138
139 bool visitExpression(const Expression& e) override {
Brian Osman79457ef2020-09-24 15:01:27 -0400140 if (e.is<VariableReference>()) {
John Stiles403a3632020-08-20 12:11:48 -0400141 const VariableReference& var = e.as<VariableReference>();
Ethan Nicholas78686922020-10-08 06:46:27 -0400142 return var.variable()->modifiers().fLayout.fBuiltin == fBuiltin;
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400143 }
John Stilesd7ab4502020-09-24 22:41:00 -0400144 return INHERITED::visitExpression(e);
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400145 }
146
Brian Osman92aac1e2020-08-05 16:48:58 -0400147 int fBuiltin;
148
John Stiles7571f9e2020-09-02 22:42:33 -0400149 using INHERITED = ProgramVisitor;
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400150};
151
Ethan Nicholas6e0fa402020-08-20 14:08:23 -0400152// Visitor that counts the number of nodes visited
153class NodeCountVisitor : public ProgramVisitor {
154public:
John Stiles2c1e4922020-10-01 09:14:14 -0400155 NodeCountVisitor(int limit) : fLimit(limit) {}
156
Ethan Nicholas6e0fa402020-08-20 14:08:23 -0400157 int visit(const Statement& s) {
Ethan Nicholas6e0fa402020-08-20 14:08:23 -0400158 this->visitStatement(s);
159 return fCount;
160 }
161
162 bool visitExpression(const Expression& e) override {
163 ++fCount;
John Stiles9b9415e2020-11-23 14:48:06 -0500164 return (fCount >= fLimit) || INHERITED::visitExpression(e);
Ethan Nicholas6e0fa402020-08-20 14:08:23 -0400165 }
166
167 bool visitProgramElement(const ProgramElement& p) override {
168 ++fCount;
John Stiles9b9415e2020-11-23 14:48:06 -0500169 return (fCount >= fLimit) || INHERITED::visitProgramElement(p);
Ethan Nicholas6e0fa402020-08-20 14:08:23 -0400170 }
171
172 bool visitStatement(const Statement& s) override {
173 ++fCount;
John Stiles9b9415e2020-11-23 14:48:06 -0500174 return (fCount >= fLimit) || INHERITED::visitStatement(s);
Ethan Nicholas6e0fa402020-08-20 14:08:23 -0400175 }
176
177private:
John Stiles2c1e4922020-10-01 09:14:14 -0400178 int fCount = 0;
179 int fLimit;
Ethan Nicholas6e0fa402020-08-20 14:08:23 -0400180
John Stiles7571f9e2020-09-02 22:42:33 -0400181 using INHERITED = ProgramVisitor;
Ethan Nicholas6e0fa402020-08-20 14:08:23 -0400182};
183
Brian Osman010ce6a2020-10-19 16:34:10 -0400184class ProgramUsageVisitor : public ProgramVisitor {
Brian Osman2e25ff42020-10-15 10:32:04 -0400185public:
Brian Osman010ce6a2020-10-19 16:34:10 -0400186 ProgramUsageVisitor(ProgramUsage* usage, int delta) : fUsage(usage), fDelta(delta) {}
187
Brian Osman2e25ff42020-10-15 10:32:04 -0400188 bool visitExpression(const Expression& e) override {
189 if (e.is<FunctionCall>()) {
190 const FunctionDeclaration* f = &e.as<FunctionCall>().function();
Brian Osman010ce6a2020-10-19 16:34:10 -0400191 fUsage->fCallCounts[f] += fDelta;
192 SkASSERT(fUsage->fCallCounts[f] >= 0);
193 } else if (e.is<VariableReference>()) {
194 const VariableReference& ref = e.as<VariableReference>();
195 ProgramUsage::VariableCounts& counts = fUsage->fVariableCounts[ref.variable()];
196 switch (ref.refKind()) {
197 case VariableRefKind::kRead:
198 counts.fRead += fDelta;
199 break;
200 case VariableRefKind::kWrite:
201 counts.fWrite += fDelta;
202 break;
203 case VariableRefKind::kReadWrite:
204 case VariableRefKind::kPointer:
205 counts.fRead += fDelta;
206 counts.fWrite += fDelta;
207 break;
208 }
209 SkASSERT(counts.fRead >= 0 && counts.fWrite >= 0);
Brian Osman2e25ff42020-10-15 10:32:04 -0400210 }
211 return INHERITED::visitExpression(e);
212 }
213
Brian Osman010ce6a2020-10-19 16:34:10 -0400214 using ProgramVisitor::visitProgramElement;
215 using ProgramVisitor::visitStatement;
216
217 ProgramUsage* fUsage;
218 int fDelta;
Brian Osman2e25ff42020-10-15 10:32:04 -0400219 using INHERITED = ProgramVisitor;
220};
221
Ethan Nicholas765d2fe2020-08-26 08:29:55 -0400222class VariableWriteVisitor : public ProgramVisitor {
223public:
224 VariableWriteVisitor(const Variable* var)
225 : fVar(var) {}
226
227 bool visit(const Statement& s) {
228 return this->visitStatement(s);
229 }
230
231 bool visitExpression(const Expression& e) override {
Brian Osman79457ef2020-09-24 15:01:27 -0400232 if (e.is<VariableReference>()) {
Ethan Nicholas765d2fe2020-08-26 08:29:55 -0400233 const VariableReference& ref = e.as<VariableReference>();
Ethan Nicholas453f67f2020-10-09 10:43:45 -0400234 if (ref.variable() == fVar &&
235 (ref.refKind() == VariableReference::RefKind::kWrite ||
236 ref.refKind() == VariableReference::RefKind::kReadWrite ||
237 ref.refKind() == VariableReference::RefKind::kPointer)) {
Ethan Nicholas765d2fe2020-08-26 08:29:55 -0400238 return true;
239 }
240 }
John Stilesd7ab4502020-09-24 22:41:00 -0400241 return INHERITED::visitExpression(e);
Ethan Nicholas765d2fe2020-08-26 08:29:55 -0400242 }
243
244private:
245 const Variable* fVar;
246
John Stiles7571f9e2020-09-02 22:42:33 -0400247 using INHERITED = ProgramVisitor;
Ethan Nicholas765d2fe2020-08-26 08:29:55 -0400248};
249
John Stilesa976da72020-09-25 23:06:26 -0400250// If a caller doesn't care about errors, we can use this trivial reporter that just counts up.
251class TrivialErrorReporter : public ErrorReporter {
252public:
253 void error(int offset, String) override { ++fErrorCount; }
254 int errorCount() override { return fErrorCount; }
255
256private:
257 int fErrorCount = 0;
258};
259
John Stilesdce4d3e2020-09-25 14:35:13 -0400260// This isn't actually using ProgramVisitor, because it only considers a subset of the fields for
261// any given expression kind. For instance, when indexing an array (e.g. `x[1]`), we only want to
262// know if the base (`x`) is assignable; the index expression (`1`) doesn't need to be.
263class IsAssignableVisitor {
264public:
John Stilesa976da72020-09-25 23:06:26 -0400265 IsAssignableVisitor(VariableReference** assignableVar, ErrorReporter* errors)
266 : fAssignableVar(assignableVar), fErrors(errors) {
267 if (fAssignableVar) {
268 *fAssignableVar = nullptr;
269 }
270 }
John Stilesdce4d3e2020-09-25 14:35:13 -0400271
272 bool visit(Expression& expr) {
273 this->visitExpression(expr);
John Stilesa976da72020-09-25 23:06:26 -0400274 return fErrors->errorCount() == 0;
John Stilesdce4d3e2020-09-25 14:35:13 -0400275 }
276
277 void visitExpression(Expression& expr) {
278 switch (expr.kind()) {
279 case Expression::Kind::kVariableReference: {
280 VariableReference& varRef = expr.as<VariableReference>();
Ethan Nicholas78686922020-10-08 06:46:27 -0400281 const Variable* var = varRef.variable();
Ethan Nicholas041fd0a2020-10-07 16:42:04 -0400282 if (var->modifiers().fFlags & (Modifiers::kConst_Flag | Modifiers::kUniform_Flag |
283 Modifiers::kVarying_Flag)) {
John Stilesa976da72020-09-25 23:06:26 -0400284 fErrors->error(expr.fOffset,
Ethan Nicholase2c49992020-10-05 11:49:11 -0400285 "cannot modify immutable variable '" + var->name() + "'");
John Stilesa976da72020-09-25 23:06:26 -0400286 } else if (fAssignableVar) {
287 SkASSERT(*fAssignableVar == nullptr);
288 *fAssignableVar = &varRef;
John Stilesdce4d3e2020-09-25 14:35:13 -0400289 }
290 break;
291 }
292 case Expression::Kind::kFieldAccess:
Ethan Nicholas7a95b202020-10-09 11:55:40 -0400293 this->visitExpression(*expr.as<FieldAccess>().base());
John Stilesdce4d3e2020-09-25 14:35:13 -0400294 break;
295
296 case Expression::Kind::kSwizzle: {
297 const Swizzle& swizzle = expr.as<Swizzle>();
298 this->checkSwizzleWrite(swizzle);
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400299 this->visitExpression(*swizzle.base());
John Stilesdce4d3e2020-09-25 14:35:13 -0400300 break;
301 }
302 case Expression::Kind::kIndex:
Ethan Nicholas2a4952d2020-10-08 15:35:56 -0400303 this->visitExpression(*expr.as<IndexExpression>().base());
John Stilesdce4d3e2020-09-25 14:35:13 -0400304 break;
305
John Stilesdce4d3e2020-09-25 14:35:13 -0400306 case Expression::Kind::kExternalValue: {
Ethan Nicholas444ccc62020-10-09 10:16:22 -0400307 const ExternalValue& var = expr.as<ExternalValueReference>().value();
308 if (!var.canWrite()) {
John Stilesa976da72020-09-25 23:06:26 -0400309 fErrors->error(expr.fOffset,
Ethan Nicholas444ccc62020-10-09 10:16:22 -0400310 "cannot modify immutable external value '" + var.name() + "'");
John Stilesdce4d3e2020-09-25 14:35:13 -0400311 }
312 break;
313 }
314 default:
John Stilesa976da72020-09-25 23:06:26 -0400315 fErrors->error(expr.fOffset, "cannot assign to this expression");
John Stilesdce4d3e2020-09-25 14:35:13 -0400316 break;
317 }
318 }
319
320private:
321 void checkSwizzleWrite(const Swizzle& swizzle) {
322 int bits = 0;
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400323 for (int idx : swizzle.components()) {
John Stilesdce4d3e2020-09-25 14:35:13 -0400324 SkASSERT(idx <= 3);
325 int bit = 1 << idx;
326 if (bits & bit) {
John Stilesa976da72020-09-25 23:06:26 -0400327 fErrors->error(swizzle.fOffset,
328 "cannot write to the same swizzle field more than once");
John Stilesdce4d3e2020-09-25 14:35:13 -0400329 break;
330 }
331 bits |= bit;
332 }
333 }
334
John Stilesa976da72020-09-25 23:06:26 -0400335 VariableReference** fAssignableVar;
336 ErrorReporter* fErrors;
John Stilesdce4d3e2020-09-25 14:35:13 -0400337
338 using INHERITED = ProgramVisitor;
339};
340
John Stilesa6841be2020-08-06 14:11:56 -0400341} // namespace
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400342
343////////////////////////////////////////////////////////////////////////////////
344// Analysis
345
Brian Osman1298bc42020-06-30 13:39:35 -0400346SampleUsage Analysis::GetSampleUsage(const Program& program, const Variable& fp) {
John Stiles933abe32020-08-28 11:58:40 -0400347 MergeSampleUsageVisitor visitor(*program.fContext, fp);
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400348 return visitor.visit(program);
349}
350
Brian Osman92aac1e2020-08-05 16:48:58 -0400351bool Analysis::ReferencesBuiltin(const Program& program, int builtin) {
352 BuiltinVariableVisitor visitor(builtin);
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400353 return visitor.visit(program);
354}
355
Brian Osman92aac1e2020-08-05 16:48:58 -0400356bool Analysis::ReferencesSampleCoords(const Program& program) {
357 return Analysis::ReferencesBuiltin(program, SK_MAIN_COORDS_BUILTIN);
358}
359
360bool Analysis::ReferencesFragCoords(const Program& program) {
361 return Analysis::ReferencesBuiltin(program, SK_FRAGCOORD_BUILTIN);
362}
363
John Stiles9b9415e2020-11-23 14:48:06 -0500364int Analysis::NodeCountUpToLimit(const FunctionDefinition& function, int limit) {
365 return NodeCountVisitor{limit}.visit(*function.body());
Ethan Nicholas6e0fa402020-08-20 14:08:23 -0400366}
367
Brian Osman010ce6a2020-10-19 16:34:10 -0400368std::unique_ptr<ProgramUsage> Analysis::GetUsage(const Program& program) {
369 auto usage = std::make_unique<ProgramUsage>();
370 ProgramUsageVisitor addRefs(usage.get(), /*delta=*/+1);
371 addRefs.visit(program);
372 return usage;
373}
374
Brian Osman0006ad02020-11-18 15:38:39 -0500375std::unique_ptr<ProgramUsage> Analysis::GetUsage(const LoadedModule& module) {
376 auto usage = std::make_unique<ProgramUsage>();
377 ProgramUsageVisitor addRefs(usage.get(), /*delta=*/+1);
378 for (const auto& element : module.fElements) {
379 addRefs.visitProgramElement(*element);
380 }
381 return usage;
382}
383
Brian Osman010ce6a2020-10-19 16:34:10 -0400384ProgramUsage::VariableCounts ProgramUsage::get(const Variable& v) const {
385 VariableCounts result = { 0, v.initialValue() ? 1 : 0 };
386 if (const VariableCounts* counts = fVariableCounts.find(&v)) {
387 result.fRead += counts->fRead;
388 result.fWrite += counts->fWrite;
389 }
390 return result;
391}
392
393bool ProgramUsage::isDead(const Variable& v) const {
394 const Modifiers& modifiers = v.modifiers();
395 VariableCounts counts = this->get(v);
396 if ((v.storage() != Variable::Storage::kLocal && counts.fRead) ||
397 (modifiers.fFlags & (Modifiers::kIn_Flag | Modifiers::kOut_Flag | Modifiers::kUniform_Flag |
398 Modifiers::kVarying_Flag))) {
399 return false;
400 }
401 return !counts.fWrite || (!counts.fRead && !(modifiers.fFlags &
402 (Modifiers::kPLS_Flag | Modifiers::kPLSOut_Flag)));
403}
404
405int ProgramUsage::get(const FunctionDeclaration& f) const {
406 const int* count = fCallCounts.find(&f);
407 return count ? *count : 0;
408}
409
410void ProgramUsage::replace(const Expression* oldExpr, const Expression* newExpr) {
411 if (oldExpr) {
412 ProgramUsageVisitor subRefs(this, /*delta=*/-1);
413 subRefs.visitExpression(*oldExpr);
414 }
415 if (newExpr) {
416 ProgramUsageVisitor addRefs(this, /*delta=*/+1);
417 addRefs.visitExpression(*newExpr);
418 }
419}
420
421void ProgramUsage::add(const Statement* stmt) {
422 ProgramUsageVisitor addRefs(this, /*delta=*/+1);
423 addRefs.visitStatement(*stmt);
424}
425
426void ProgramUsage::remove(const Expression* expr) {
427 ProgramUsageVisitor subRefs(this, /*delta=*/-1);
428 subRefs.visitExpression(*expr);
429}
430
431void ProgramUsage::remove(const Statement* stmt) {
432 ProgramUsageVisitor subRefs(this, /*delta=*/-1);
433 subRefs.visitStatement(*stmt);
434}
435
436void ProgramUsage::remove(const ProgramElement& element) {
437 ProgramUsageVisitor subRefs(this, /*delta=*/-1);
438 subRefs.visitProgramElement(element);
Brian Osman2e25ff42020-10-15 10:32:04 -0400439}
440
Ethan Nicholas765d2fe2020-08-26 08:29:55 -0400441bool Analysis::StatementWritesToVariable(const Statement& stmt, const Variable& var) {
442 return VariableWriteVisitor(&var).visit(stmt);
443}
444
John Stilesa976da72020-09-25 23:06:26 -0400445bool Analysis::IsAssignable(Expression& expr, VariableReference** assignableVar,
446 ErrorReporter* errors) {
447 TrivialErrorReporter trivialErrors;
448 return IsAssignableVisitor{assignableVar, errors ? errors : &trivialErrors}.visit(expr);
John Stilesdce4d3e2020-09-25 14:35:13 -0400449}
450
John Stilesc30fbca2020-11-19 16:25:49 -0500451bool Analysis::IsTrivialExpression(const Expression& expr) {
452 return expr.is<IntLiteral>() ||
453 expr.is<FloatLiteral>() ||
454 expr.is<BoolLiteral>() ||
455 expr.is<VariableReference>() ||
456 (expr.is<Swizzle>() &&
457 IsTrivialExpression(*expr.as<Swizzle>().base())) ||
458 (expr.is<FieldAccess>() &&
459 IsTrivialExpression(*expr.as<FieldAccess>().base())) ||
460 (expr.is<Constructor>() &&
461 expr.as<Constructor>().arguments().size() == 1 &&
462 IsTrivialExpression(*expr.as<Constructor>().arguments().front())) ||
463 (expr.is<Constructor>() &&
464 expr.isConstantOrUniform()) ||
465 (expr.is<IndexExpression>() &&
466 expr.as<IndexExpression>().index()->is<IntLiteral>() &&
467 IsTrivialExpression(*expr.as<IndexExpression>().base()));
468}
469
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400470////////////////////////////////////////////////////////////////////////////////
471// ProgramVisitor
472
Brian Osman133724c2020-10-28 14:14:39 -0400473bool ProgramVisitor::visit(const Program& program) {
474 for (const ProgramElement* pe : program.elements()) {
Brian Osman1179fcf2020-10-08 16:04:40 -0400475 if (this->visitProgramElement(*pe)) {
John Stiles933abe32020-08-28 11:58:40 -0400476 return true;
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400477 }
478 }
John Stiles933abe32020-08-28 11:58:40 -0400479 return false;
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400480}
481
John Stiles70b82422020-09-30 10:55:12 -0400482template <typename PROG, typename EXPR, typename STMT, typename ELEM>
483bool TProgramVisitor<PROG, EXPR, STMT, ELEM>::visitExpression(EXPR e) {
484 switch (e.kind()) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400485 case Expression::Kind::kBoolLiteral:
486 case Expression::Kind::kDefined:
487 case Expression::Kind::kExternalValue:
Ethan Nicholase6592142020-09-08 10:22:09 -0400488 case Expression::Kind::kFloatLiteral:
489 case Expression::Kind::kFunctionReference:
490 case Expression::Kind::kIntLiteral:
491 case Expression::Kind::kNullLiteral:
492 case Expression::Kind::kSetting:
493 case Expression::Kind::kTypeReference:
494 case Expression::Kind::kVariableReference:
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400495 // Leaf expressions return false
496 return false;
John Stiles70b82422020-09-30 10:55:12 -0400497
Ethan Nicholase6592142020-09-08 10:22:09 -0400498 case Expression::Kind::kBinary: {
John Stiles70b82422020-09-30 10:55:12 -0400499 auto& b = e.template as<BinaryExpression>();
John Stiles2d4f9592020-10-30 10:29:12 -0400500 return (b.left() && this->visitExpression(*b.left())) ||
501 (b.right() && this->visitExpression(*b.right()));
John Stiles70b82422020-09-30 10:55:12 -0400502 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400503 case Expression::Kind::kConstructor: {
John Stiles70b82422020-09-30 10:55:12 -0400504 auto& c = e.template as<Constructor>();
505 for (auto& arg : c.arguments()) {
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400506 if (this->visitExpression(*arg)) { return true; }
507 }
John Stiles70b82422020-09-30 10:55:12 -0400508 return false;
509 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400510 case Expression::Kind::kExternalFunctionCall: {
John Stiles70b82422020-09-30 10:55:12 -0400511 auto& c = e.template as<ExternalFunctionCall>();
Ethan Nicholas6e86ec92020-09-30 14:29:56 -0400512 for (auto& arg : c.arguments()) {
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400513 if (this->visitExpression(*arg)) { return true; }
514 }
John Stiles70b82422020-09-30 10:55:12 -0400515 return false;
516 }
John Stilesd7ab4502020-09-24 22:41:00 -0400517 case Expression::Kind::kFieldAccess:
Ethan Nicholas7a95b202020-10-09 11:55:40 -0400518 return this->visitExpression(*e.template as<FieldAccess>().base());
John Stiles70b82422020-09-30 10:55:12 -0400519
Ethan Nicholase6592142020-09-08 10:22:09 -0400520 case Expression::Kind::kFunctionCall: {
John Stiles70b82422020-09-30 10:55:12 -0400521 auto& c = e.template as<FunctionCall>();
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400522 for (auto& arg : c.arguments()) {
Brian Osman010ce6a2020-10-19 16:34:10 -0400523 if (arg && this->visitExpression(*arg)) { return true; }
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400524 }
John Stiles70b82422020-09-30 10:55:12 -0400525 return false;
526 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400527 case Expression::Kind::kIndex: {
John Stiles70b82422020-09-30 10:55:12 -0400528 auto& i = e.template as<IndexExpression>();
Ethan Nicholas2a4952d2020-10-08 15:35:56 -0400529 return this->visitExpression(*i.base()) || this->visitExpression(*i.index());
John Stiles70b82422020-09-30 10:55:12 -0400530 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400531 case Expression::Kind::kPostfix:
Ethan Nicholas444ccc62020-10-09 10:16:22 -0400532 return this->visitExpression(*e.template as<PostfixExpression>().operand());
John Stiles70b82422020-09-30 10:55:12 -0400533
Ethan Nicholase6592142020-09-08 10:22:09 -0400534 case Expression::Kind::kPrefix:
Ethan Nicholas444ccc62020-10-09 10:16:22 -0400535 return this->visitExpression(*e.template as<PrefixExpression>().operand());
John Stiles70b82422020-09-30 10:55:12 -0400536
Brian Osman010ce6a2020-10-19 16:34:10 -0400537 case Expression::Kind::kSwizzle: {
538 auto& s = e.template as<Swizzle>();
539 return s.base() && this->visitExpression(*s.base());
540 }
John Stiles70b82422020-09-30 10:55:12 -0400541
Ethan Nicholase6592142020-09-08 10:22:09 -0400542 case Expression::Kind::kTernary: {
John Stiles70b82422020-09-30 10:55:12 -0400543 auto& t = e.template as<TernaryExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400544 return this->visitExpression(*t.test()) ||
545 (t.ifTrue() && this->visitExpression(*t.ifTrue())) ||
546 (t.ifFalse() && this->visitExpression(*t.ifFalse()));
John Stiles70b82422020-09-30 10:55:12 -0400547 }
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400548 default:
549 SkUNREACHABLE;
550 }
551}
552
John Stiles70b82422020-09-30 10:55:12 -0400553template <typename PROG, typename EXPR, typename STMT, typename ELEM>
554bool TProgramVisitor<PROG, EXPR, STMT, ELEM>::visitStatement(STMT s) {
555 switch (s.kind()) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400556 case Statement::Kind::kBreak:
557 case Statement::Kind::kContinue:
558 case Statement::Kind::kDiscard:
John Stiles98c1f822020-09-09 14:18:53 -0400559 case Statement::Kind::kInlineMarker:
Ethan Nicholase6592142020-09-08 10:22:09 -0400560 case Statement::Kind::kNop:
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400561 // Leaf statements just return false
562 return false;
John Stiles70b82422020-09-30 10:55:12 -0400563
Ethan Nicholase6592142020-09-08 10:22:09 -0400564 case Statement::Kind::kBlock:
John Stiles70b82422020-09-30 10:55:12 -0400565 for (auto& stmt : s.template as<Block>().children()) {
Brian Osman010ce6a2020-10-19 16:34:10 -0400566 if (stmt && this->visitStatement(*stmt)) {
Ethan Nicholas7bd60432020-09-25 14:31:59 -0400567 return true;
568 }
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400569 }
570 return false;
John Stiles70b82422020-09-30 10:55:12 -0400571
Ethan Nicholase6592142020-09-08 10:22:09 -0400572 case Statement::Kind::kDo: {
John Stiles70b82422020-09-30 10:55:12 -0400573 auto& d = s.template as<DoStatement>();
574 return this->visitExpression(*d.test()) || this->visitStatement(*d.statement());
575 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400576 case Statement::Kind::kExpression:
John Stiles70b82422020-09-30 10:55:12 -0400577 return this->visitExpression(*s.template as<ExpressionStatement>().expression());
578
Ethan Nicholase6592142020-09-08 10:22:09 -0400579 case Statement::Kind::kFor: {
John Stiles70b82422020-09-30 10:55:12 -0400580 auto& f = s.template as<ForStatement>();
Ethan Nicholas0d31ed52020-10-05 14:47:09 -0400581 return (f.initializer() && this->visitStatement(*f.initializer())) ||
582 (f.test() && this->visitExpression(*f.test())) ||
583 (f.next() && this->visitExpression(*f.next())) ||
584 this->visitStatement(*f.statement());
John Stiles70b82422020-09-30 10:55:12 -0400585 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400586 case Statement::Kind::kIf: {
John Stiles70b82422020-09-30 10:55:12 -0400587 auto& i = s.template as<IfStatement>();
Brian Osman5567a602020-10-27 09:52:39 -0400588 return (i.test() && this->visitExpression(*i.test())) ||
Brian Osman010ce6a2020-10-19 16:34:10 -0400589 (i.ifTrue() && this->visitStatement(*i.ifTrue())) ||
Ethan Nicholas8c44eca2020-10-07 16:47:09 -0400590 (i.ifFalse() && this->visitStatement(*i.ifFalse()));
John Stiles70b82422020-09-30 10:55:12 -0400591 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400592 case Statement::Kind::kReturn: {
John Stiles70b82422020-09-30 10:55:12 -0400593 auto& r = s.template as<ReturnStatement>();
Ethan Nicholas2a4952d2020-10-08 15:35:56 -0400594 return r.expression() && this->visitExpression(*r.expression());
John Stiles70b82422020-09-30 10:55:12 -0400595 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400596 case Statement::Kind::kSwitch: {
John Stiles70b82422020-09-30 10:55:12 -0400597 auto& sw = s.template as<SwitchStatement>();
Ethan Nicholas01b05e52020-10-22 15:53:41 -0400598 if (this->visitExpression(*sw.value())) {
John Stiles70b82422020-09-30 10:55:12 -0400599 return true;
600 }
Ethan Nicholas01b05e52020-10-22 15:53:41 -0400601 for (const auto& c : sw.cases()) {
John Stiles2d4f9592020-10-30 10:29:12 -0400602 if (c->value() && this->visitExpression(*c->value())) {
John Stiles70b82422020-09-30 10:55:12 -0400603 return true;
604 }
John Stiles2d4f9592020-10-30 10:29:12 -0400605 for (auto& st : c->statements()) {
Brian Osman010ce6a2020-10-19 16:34:10 -0400606 if (st && this->visitStatement(*st)) {
John Stiles70b82422020-09-30 10:55:12 -0400607 return true;
608 }
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400609 }
610 }
John Stiles70b82422020-09-30 10:55:12 -0400611 return false;
612 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400613 case Statement::Kind::kVarDeclaration: {
John Stiles70b82422020-09-30 10:55:12 -0400614 auto& v = s.template as<VarDeclaration>();
John Stiles2d4f9592020-10-30 10:29:12 -0400615 for (const std::unique_ptr<Expression>& size : v.sizes()) {
616 if (size && this->visitExpression(*size)) {
John Stiles70b82422020-09-30 10:55:12 -0400617 return true;
618 }
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400619 }
Ethan Nicholasc51f33e2020-10-13 13:49:44 -0400620 return v.value() && this->visitExpression(*v.value());
John Stiles70b82422020-09-30 10:55:12 -0400621 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400622 case Statement::Kind::kWhile: {
John Stiles70b82422020-09-30 10:55:12 -0400623 auto& w = s.template as<WhileStatement>();
Ethan Nicholas2a4952d2020-10-08 15:35:56 -0400624 return this->visitExpression(*w.test()) || this->visitStatement(*w.statement());
John Stiles70b82422020-09-30 10:55:12 -0400625 }
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400626 default:
627 SkUNREACHABLE;
628 }
629}
630
John Stiles70b82422020-09-30 10:55:12 -0400631template <typename PROG, typename EXPR, typename STMT, typename ELEM>
632bool TProgramVisitor<PROG, EXPR, STMT, ELEM>::visitProgramElement(ELEM pe) {
633 switch (pe.kind()) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400634 case ProgramElement::Kind::kEnum:
635 case ProgramElement::Kind::kExtension:
John Stiles569249b2020-11-03 12:18:22 -0500636 case ProgramElement::Kind::kFunctionPrototype:
Ethan Nicholase6592142020-09-08 10:22:09 -0400637 case ProgramElement::Kind::kModifiers:
638 case ProgramElement::Kind::kSection:
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400639 // Leaf program elements just return false by default
640 return false;
John Stiles70b82422020-09-30 10:55:12 -0400641
Ethan Nicholase6592142020-09-08 10:22:09 -0400642 case ProgramElement::Kind::kFunction:
Ethan Nicholas0a5d0962020-10-14 13:33:18 -0400643 return this->visitStatement(*pe.template as<FunctionDefinition>().body());
John Stiles70b82422020-09-30 10:55:12 -0400644
Ethan Nicholase6592142020-09-08 10:22:09 -0400645 case ProgramElement::Kind::kInterfaceBlock:
Ethan Nicholaseaf47882020-10-15 10:10:08 -0400646 for (auto& e : pe.template as<InterfaceBlock>().sizes()) {
Ethan Nicholas825268f2020-10-02 16:26:00 -0400647 if (e && this->visitExpression(*e)) {
John Stiles70b82422020-09-30 10:55:12 -0400648 return true;
649 }
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400650 }
651 return false;
John Stiles70b82422020-09-30 10:55:12 -0400652
Brian Osmanc0213602020-10-06 14:43:32 -0400653 case ProgramElement::Kind::kGlobalVar:
Ethan Nicholasc51f33e2020-10-13 13:49:44 -0400654 if (this->visitStatement(*pe.template as<GlobalVarDeclaration>().declaration())) {
Brian Osmanc0213602020-10-06 14:43:32 -0400655 return true;
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400656 }
657 return false;
John Stiles70b82422020-09-30 10:55:12 -0400658
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400659 default:
660 SkUNREACHABLE;
661 }
662}
663
John Stiles70b82422020-09-30 10:55:12 -0400664template class TProgramVisitor<const Program&, const Expression&,
665 const Statement&, const ProgramElement&>;
666template class TProgramVisitor<Program&, Expression&, Statement&, ProgramElement&>;
667
John Stilesa6841be2020-08-06 14:11:56 -0400668} // namespace SkSL