blob: 8f69d11300d2ce7d9a73970d3dd4143e4efdc9d8 [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
Ethan Nicholasdaed2592021-03-04 14:30:25 -050010#include "include/private/SkSLModifiers.h"
Ethan Nicholas24c17722021-03-09 13:10:59 -050011#include "include/private/SkSLProgramElement.h"
Brian Osman1298bc42020-06-30 13:39:35 -040012#include "include/private/SkSLSampleUsage.h"
Ethan Nicholas24c17722021-03-09 13:10:59 -050013#include "include/private/SkSLStatement.h"
Ethan Nicholas4a5e22a2021-08-13 17:29:51 -040014#include "include/sksl/SkSLErrorReporter.h"
John Stiles61e5e202021-09-02 09:56:31 -040015#include "src/core/SkSafeMath.h"
Brian Osman00185012021-02-04 16:07:11 -050016#include "src/sksl/SkSLCompiler.h"
Michael Ludwig8f3a8362020-06-29 17:27:00 -040017#include "src/sksl/ir/SkSLExpression.h"
18#include "src/sksl/ir/SkSLProgram.h"
Michael Ludwig8f3a8362020-06-29 17:27:00 -040019
20// ProgramElements
Michael Ludwig8f3a8362020-06-29 17:27:00 -040021#include "src/sksl/ir/SkSLExtension.h"
22#include "src/sksl/ir/SkSLFunctionDefinition.h"
23#include "src/sksl/ir/SkSLInterfaceBlock.h"
Michael Ludwig8f3a8362020-06-29 17:27:00 -040024#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
39// Expressions
40#include "src/sksl/ir/SkSLBinaryExpression.h"
41#include "src/sksl/ir/SkSLBoolLiteral.h"
Brian Osmaneb0f29d2021-08-04 11:34:16 -040042#include "src/sksl/ir/SkSLChildCall.h"
Michael Ludwig8f3a8362020-06-29 17:27:00 -040043#include "src/sksl/ir/SkSLConstructor.h"
John Stilese1182782021-03-30 22:09:37 -040044#include "src/sksl/ir/SkSLConstructorDiagonalMatrix.h"
John Stiles5abb9e12021-04-06 13:47:19 -040045#include "src/sksl/ir/SkSLConstructorMatrixResize.h"
Michael Ludwig8f3a8362020-06-29 17:27:00 -040046#include "src/sksl/ir/SkSLExternalFunctionCall.h"
Brian Osmanbe0b3b72021-01-06 14:27:35 -050047#include "src/sksl/ir/SkSLExternalFunctionReference.h"
Michael Ludwig8f3a8362020-06-29 17:27:00 -040048#include "src/sksl/ir/SkSLFieldAccess.h"
49#include "src/sksl/ir/SkSLFloatLiteral.h"
50#include "src/sksl/ir/SkSLFunctionCall.h"
51#include "src/sksl/ir/SkSLFunctionReference.h"
52#include "src/sksl/ir/SkSLIndexExpression.h"
John Stiles98c1f822020-09-09 14:18:53 -040053#include "src/sksl/ir/SkSLInlineMarker.h"
Michael Ludwig8f3a8362020-06-29 17:27:00 -040054#include "src/sksl/ir/SkSLIntLiteral.h"
Michael Ludwig8f3a8362020-06-29 17:27:00 -040055#include "src/sksl/ir/SkSLPostfixExpression.h"
56#include "src/sksl/ir/SkSLPrefixExpression.h"
57#include "src/sksl/ir/SkSLSetting.h"
58#include "src/sksl/ir/SkSLSwizzle.h"
59#include "src/sksl/ir/SkSLTernaryExpression.h"
60#include "src/sksl/ir/SkSLTypeReference.h"
61#include "src/sksl/ir/SkSLVariableReference.h"
62
63namespace SkSL {
64
65namespace {
66
Brian Osmaneb0f29d2021-08-04 11:34:16 -040067// Visitor that determines the merged SampleUsage for a given child in the program.
Brian Osman1298bc42020-06-30 13:39:35 -040068class MergeSampleUsageVisitor : public ProgramVisitor {
Michael Ludwig8f3a8362020-06-29 17:27:00 -040069public:
Brian Osmaneb0f29d2021-08-04 11:34:16 -040070 MergeSampleUsageVisitor(const Context& context,
71 const Variable& child,
72 bool writesToSampleCoords)
73 : fContext(context), fChild(child), fWritesToSampleCoords(writesToSampleCoords) {}
Michael Ludwig8f3a8362020-06-29 17:27:00 -040074
Brian Osman1298bc42020-06-30 13:39:35 -040075 SampleUsage visit(const Program& program) {
76 fUsage = SampleUsage(); // reset to none
John Stilesd7ab4502020-09-24 22:41:00 -040077 INHERITED::visit(program);
Brian Osman1298bc42020-06-30 13:39:35 -040078 return fUsage;
Michael Ludwig8f3a8362020-06-29 17:27:00 -040079 }
80
Brian Osman8cdf28f2021-05-24 09:52:39 -040081 int elidedSampleCoordCount() const { return fElidedSampleCoordCount; }
82
Michael Ludwig8f3a8362020-06-29 17:27:00 -040083protected:
John Stiles933abe32020-08-28 11:58:40 -040084 const Context& fContext;
Brian Osmaneb0f29d2021-08-04 11:34:16 -040085 const Variable& fChild;
Brian Osman4d571112021-04-27 09:10:10 -040086 const bool fWritesToSampleCoords;
Brian Osman1298bc42020-06-30 13:39:35 -040087 SampleUsage fUsage;
Brian Osman8cdf28f2021-05-24 09:52:39 -040088 int fElidedSampleCoordCount = 0;
Michael Ludwig8f3a8362020-06-29 17:27:00 -040089
90 bool visitExpression(const Expression& e) override {
Brian Osmaneb0f29d2021-08-04 11:34:16 -040091 // Looking for child(...)
92 if (e.is<ChildCall>() && &e.as<ChildCall>().child() == &fChild) {
93 // Determine the type of call at this site, and merge it with the accumulated state
94 const ExpressionArray& arguments = e.as<ChildCall>().arguments();
95 SkASSERT(arguments.size() >= 1);
96
97 const Expression* maybeCoords = arguments[0].get();
98 if (maybeCoords->type() == *fContext.fTypes.fFloat2) {
99 // If the coords are a direct reference to the program's sample-coords, and those
100 // coords are never modified, we can conservatively turn this into PassThrough
101 // sampling. In all other cases, we consider it Explicit.
102 if (!fWritesToSampleCoords && maybeCoords->is<VariableReference>() &&
103 maybeCoords->as<VariableReference>().variable()->modifiers().fLayout.fBuiltin ==
104 SK_MAIN_COORDS_BUILTIN) {
Brian Osman1298bc42020-06-30 13:39:35 -0400105 fUsage.merge(SampleUsage::PassThrough());
Brian Osmaneb0f29d2021-08-04 11:34:16 -0400106 ++fElidedSampleCoordCount;
107 } else {
108 fUsage.merge(SampleUsage::Explicit());
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400109 }
Brian Osmaneb0f29d2021-08-04 11:34:16 -0400110 } else {
111 // child(inputColor) or child(srcColor, dstColor) -> PassThrough
112 fUsage.merge(SampleUsage::PassThrough());
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400113 }
114 }
115
John Stilesd7ab4502020-09-24 22:41:00 -0400116 return INHERITED::visitExpression(e);
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400117 }
118
John Stiles7571f9e2020-09-02 22:42:33 -0400119 using INHERITED = ProgramVisitor;
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400120};
121
Brian Osman92aac1e2020-08-05 16:48:58 -0400122// Visitor that searches through the program for references to a particular builtin variable
123class BuiltinVariableVisitor : public ProgramVisitor {
124public:
125 BuiltinVariableVisitor(int builtin) : fBuiltin(builtin) {}
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400126
127 bool visitExpression(const Expression& e) override {
Brian Osman79457ef2020-09-24 15:01:27 -0400128 if (e.is<VariableReference>()) {
John Stiles403a3632020-08-20 12:11:48 -0400129 const VariableReference& var = e.as<VariableReference>();
Ethan Nicholas78686922020-10-08 06:46:27 -0400130 return var.variable()->modifiers().fLayout.fBuiltin == fBuiltin;
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400131 }
John Stilesd7ab4502020-09-24 22:41:00 -0400132 return INHERITED::visitExpression(e);
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400133 }
134
Brian Osman92aac1e2020-08-05 16:48:58 -0400135 int fBuiltin;
136
John Stiles7571f9e2020-09-02 22:42:33 -0400137 using INHERITED = ProgramVisitor;
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400138};
139
Brian Osmaneb0f29d2021-08-04 11:34:16 -0400140// Visitor that searches for child calls from a function other than main()
Brian Osman04d79fc2021-07-02 13:25:35 -0400141class SampleOutsideMainVisitor : public ProgramVisitor {
142public:
143 SampleOutsideMainVisitor() {}
144
145 bool visitExpression(const Expression& e) override {
Brian Osmaneb0f29d2021-08-04 11:34:16 -0400146 if (e.is<ChildCall>()) {
147 return true;
Brian Osman04d79fc2021-07-02 13:25:35 -0400148 }
149 return INHERITED::visitExpression(e);
150 }
151
152 bool visitProgramElement(const ProgramElement& p) override {
153 return p.is<FunctionDefinition>() &&
154 !p.as<FunctionDefinition>().declaration().isMain() &&
155 INHERITED::visitProgramElement(p);
156 }
157
158 using INHERITED = ProgramVisitor;
159};
160
Ethan Nicholas6e0fa402020-08-20 14:08:23 -0400161// Visitor that counts the number of nodes visited
162class NodeCountVisitor : public ProgramVisitor {
163public:
John Stiles2c1e4922020-10-01 09:14:14 -0400164 NodeCountVisitor(int limit) : fLimit(limit) {}
165
Ethan Nicholas6e0fa402020-08-20 14:08:23 -0400166 int visit(const Statement& s) {
Ethan Nicholas6e0fa402020-08-20 14:08:23 -0400167 this->visitStatement(s);
168 return fCount;
169 }
170
171 bool visitExpression(const Expression& e) override {
172 ++fCount;
John Stiles9b9415e2020-11-23 14:48:06 -0500173 return (fCount >= fLimit) || INHERITED::visitExpression(e);
Ethan Nicholas6e0fa402020-08-20 14:08:23 -0400174 }
175
176 bool visitProgramElement(const ProgramElement& p) override {
177 ++fCount;
John Stiles9b9415e2020-11-23 14:48:06 -0500178 return (fCount >= fLimit) || INHERITED::visitProgramElement(p);
Ethan Nicholas6e0fa402020-08-20 14:08:23 -0400179 }
180
181 bool visitStatement(const Statement& s) override {
182 ++fCount;
John Stiles9b9415e2020-11-23 14:48:06 -0500183 return (fCount >= fLimit) || INHERITED::visitStatement(s);
Ethan Nicholas6e0fa402020-08-20 14:08:23 -0400184 }
185
186private:
John Stiles2c1e4922020-10-01 09:14:14 -0400187 int fCount = 0;
188 int fLimit;
Ethan Nicholas6e0fa402020-08-20 14:08:23 -0400189
John Stiles7571f9e2020-09-02 22:42:33 -0400190 using INHERITED = ProgramVisitor;
Ethan Nicholas6e0fa402020-08-20 14:08:23 -0400191};
192
Brian Osman010ce6a2020-10-19 16:34:10 -0400193class ProgramUsageVisitor : public ProgramVisitor {
Brian Osman2e25ff42020-10-15 10:32:04 -0400194public:
Brian Osman010ce6a2020-10-19 16:34:10 -0400195 ProgramUsageVisitor(ProgramUsage* usage, int delta) : fUsage(usage), fDelta(delta) {}
196
John Stiles39465b82021-03-18 09:19:55 -0400197 bool visitProgramElement(const ProgramElement& pe) override {
198 if (pe.is<FunctionDefinition>()) {
199 for (const Variable* param : pe.as<FunctionDefinition>().declaration().parameters()) {
200 // Ensure function-parameter variables exist in the variable usage map. They aren't
201 // otherwise declared, but ProgramUsage::get() should be able to find them, even if
202 // they are unread and unwritten.
203 fUsage->fVariableCounts[param];
204 }
John Stiles8e2a84b2021-04-19 09:35:38 -0400205 } else if (pe.is<InterfaceBlock>()) {
206 // Ensure interface-block variables exist in the variable usage map.
207 fUsage->fVariableCounts[&pe.as<InterfaceBlock>().variable()];
John Stiles39465b82021-03-18 09:19:55 -0400208 }
209 return INHERITED::visitProgramElement(pe);
210 }
211
John Stiles04a8a542021-03-10 19:03:26 -0500212 bool visitStatement(const Statement& s) override {
213 if (s.is<VarDeclaration>()) {
214 // Add all declared variables to the usage map (even if never otherwise accessed).
215 const VarDeclaration& vd = s.as<VarDeclaration>();
216 ProgramUsage::VariableCounts& counts = fUsage->fVariableCounts[&vd.var()];
217 counts.fDeclared += fDelta;
218 SkASSERT(counts.fDeclared >= 0);
219 if (vd.value()) {
220 // The initial-value expression, when present, counts as a write.
221 counts.fWrite += fDelta;
222 }
223 }
224 return INHERITED::visitStatement(s);
225 }
226
Brian Osman2e25ff42020-10-15 10:32:04 -0400227 bool visitExpression(const Expression& e) override {
228 if (e.is<FunctionCall>()) {
229 const FunctionDeclaration* f = &e.as<FunctionCall>().function();
Brian Osman010ce6a2020-10-19 16:34:10 -0400230 fUsage->fCallCounts[f] += fDelta;
231 SkASSERT(fUsage->fCallCounts[f] >= 0);
232 } else if (e.is<VariableReference>()) {
233 const VariableReference& ref = e.as<VariableReference>();
234 ProgramUsage::VariableCounts& counts = fUsage->fVariableCounts[ref.variable()];
235 switch (ref.refKind()) {
236 case VariableRefKind::kRead:
237 counts.fRead += fDelta;
238 break;
239 case VariableRefKind::kWrite:
240 counts.fWrite += fDelta;
241 break;
242 case VariableRefKind::kReadWrite:
243 case VariableRefKind::kPointer:
244 counts.fRead += fDelta;
245 counts.fWrite += fDelta;
246 break;
247 }
248 SkASSERT(counts.fRead >= 0 && counts.fWrite >= 0);
Brian Osman2e25ff42020-10-15 10:32:04 -0400249 }
250 return INHERITED::visitExpression(e);
251 }
252
Brian Osman010ce6a2020-10-19 16:34:10 -0400253 using ProgramVisitor::visitProgramElement;
254 using ProgramVisitor::visitStatement;
255
256 ProgramUsage* fUsage;
257 int fDelta;
Brian Osman2e25ff42020-10-15 10:32:04 -0400258 using INHERITED = ProgramVisitor;
259};
260
Ethan Nicholas765d2fe2020-08-26 08:29:55 -0400261class VariableWriteVisitor : public ProgramVisitor {
262public:
263 VariableWriteVisitor(const Variable* var)
264 : fVar(var) {}
265
266 bool visit(const Statement& s) {
267 return this->visitStatement(s);
268 }
269
270 bool visitExpression(const Expression& e) override {
Brian Osman79457ef2020-09-24 15:01:27 -0400271 if (e.is<VariableReference>()) {
Ethan Nicholas765d2fe2020-08-26 08:29:55 -0400272 const VariableReference& ref = e.as<VariableReference>();
Ethan Nicholas453f67f2020-10-09 10:43:45 -0400273 if (ref.variable() == fVar &&
274 (ref.refKind() == VariableReference::RefKind::kWrite ||
275 ref.refKind() == VariableReference::RefKind::kReadWrite ||
276 ref.refKind() == VariableReference::RefKind::kPointer)) {
Ethan Nicholas765d2fe2020-08-26 08:29:55 -0400277 return true;
278 }
279 }
John Stilesd7ab4502020-09-24 22:41:00 -0400280 return INHERITED::visitExpression(e);
Ethan Nicholas765d2fe2020-08-26 08:29:55 -0400281 }
282
283private:
284 const Variable* fVar;
285
John Stiles7571f9e2020-09-02 22:42:33 -0400286 using INHERITED = ProgramVisitor;
Ethan Nicholas765d2fe2020-08-26 08:29:55 -0400287};
288
John Stilesa976da72020-09-25 23:06:26 -0400289// If a caller doesn't care about errors, we can use this trivial reporter that just counts up.
290class TrivialErrorReporter : public ErrorReporter {
291public:
John Stilesbb8cf582021-08-26 23:34:59 -0400292 ~TrivialErrorReporter() override { this->reportPendingErrors({}); }
Ethan Nicholas4a5e22a2021-08-13 17:29:51 -0400293 void handleError(const char*, PositionInfo) override {}
John Stilesa976da72020-09-25 23:06:26 -0400294};
295
John Stilesdce4d3e2020-09-25 14:35:13 -0400296// This isn't actually using ProgramVisitor, because it only considers a subset of the fields for
297// any given expression kind. For instance, when indexing an array (e.g. `x[1]`), we only want to
298// know if the base (`x`) is assignable; the index expression (`1`) doesn't need to be.
299class IsAssignableVisitor {
300public:
John Stilesb21fac22020-12-04 15:36:49 -0500301 IsAssignableVisitor(ErrorReporter* errors) : fErrors(errors) {}
John Stilesdce4d3e2020-09-25 14:35:13 -0400302
John Stilesb21fac22020-12-04 15:36:49 -0500303 bool visit(Expression& expr, Analysis::AssignmentInfo* info) {
Ethan Nicholas67a0a8a2021-01-13 12:36:02 -0500304 int oldErrorCount = fErrors->errorCount();
John Stilesdce4d3e2020-09-25 14:35:13 -0400305 this->visitExpression(expr);
John Stilesb21fac22020-12-04 15:36:49 -0500306 if (info) {
307 info->fAssignedVar = fAssignedVar;
John Stilesb21fac22020-12-04 15:36:49 -0500308 }
Ethan Nicholas67a0a8a2021-01-13 12:36:02 -0500309 return fErrors->errorCount() == oldErrorCount;
John Stilesdce4d3e2020-09-25 14:35:13 -0400310 }
311
312 void visitExpression(Expression& expr) {
313 switch (expr.kind()) {
314 case Expression::Kind::kVariableReference: {
315 VariableReference& varRef = expr.as<VariableReference>();
Ethan Nicholas78686922020-10-08 06:46:27 -0400316 const Variable* var = varRef.variable();
Brian Osmane49703f2021-04-19 11:15:24 -0400317 if (var->modifiers().fFlags & (Modifiers::kConst_Flag | Modifiers::kUniform_Flag)) {
John Stilesa976da72020-09-25 23:06:26 -0400318 fErrors->error(expr.fOffset,
Ethan Nicholase2c49992020-10-05 11:49:11 -0400319 "cannot modify immutable variable '" + var->name() + "'");
John Stilesb21fac22020-12-04 15:36:49 -0500320 } else {
321 SkASSERT(fAssignedVar == nullptr);
322 fAssignedVar = &varRef;
John Stilesdce4d3e2020-09-25 14:35:13 -0400323 }
324 break;
325 }
326 case Expression::Kind::kFieldAccess:
Ethan Nicholas7a95b202020-10-09 11:55:40 -0400327 this->visitExpression(*expr.as<FieldAccess>().base());
John Stilesdce4d3e2020-09-25 14:35:13 -0400328 break;
329
330 case Expression::Kind::kSwizzle: {
331 const Swizzle& swizzle = expr.as<Swizzle>();
332 this->checkSwizzleWrite(swizzle);
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400333 this->visitExpression(*swizzle.base());
John Stilesdce4d3e2020-09-25 14:35:13 -0400334 break;
335 }
John Stiles47c0a742021-02-09 09:30:35 -0500336 case Expression::Kind::kIndex:
337 this->visitExpression(*expr.as<IndexExpression>().base());
John Stilesdce4d3e2020-09-25 14:35:13 -0400338 break;
John Stiles47c0a742021-02-09 09:30:35 -0500339
Ethan Nicholasc898d042021-08-28 19:53:34 -0400340 case Expression::Kind::kPoison:
341 break;
342
John Stilesdce4d3e2020-09-25 14:35:13 -0400343 default:
John Stilesa976da72020-09-25 23:06:26 -0400344 fErrors->error(expr.fOffset, "cannot assign to this expression");
John Stilesdce4d3e2020-09-25 14:35:13 -0400345 break;
346 }
347 }
348
349private:
350 void checkSwizzleWrite(const Swizzle& swizzle) {
351 int bits = 0;
John Stiles6e88e042021-02-19 14:09:38 -0500352 for (int8_t idx : swizzle.components()) {
353 SkASSERT(idx >= SwizzleComponent::X && idx <= SwizzleComponent::W);
John Stilesdce4d3e2020-09-25 14:35:13 -0400354 int bit = 1 << idx;
355 if (bits & bit) {
John Stilesa976da72020-09-25 23:06:26 -0400356 fErrors->error(swizzle.fOffset,
357 "cannot write to the same swizzle field more than once");
John Stilesdce4d3e2020-09-25 14:35:13 -0400358 break;
359 }
360 bits |= bit;
361 }
362 }
363
John Stilesa976da72020-09-25 23:06:26 -0400364 ErrorReporter* fErrors;
John Stilesb21fac22020-12-04 15:36:49 -0500365 VariableReference* fAssignedVar = nullptr;
John Stilesdce4d3e2020-09-25 14:35:13 -0400366
367 using INHERITED = ProgramVisitor;
368};
369
John Stiles642cde22021-02-23 14:57:01 -0500370class SwitchCaseContainsExit : public ProgramVisitor {
371public:
372 SwitchCaseContainsExit(bool conditionalExits) : fConditionalExits(conditionalExits) {}
373
374 bool visitStatement(const Statement& stmt) override {
375 switch (stmt.kind()) {
376 case Statement::Kind::kBlock:
John Stilesa0e56e32021-03-03 13:14:37 -0500377 case Statement::Kind::kSwitchCase:
John Stiles642cde22021-02-23 14:57:01 -0500378 return INHERITED::visitStatement(stmt);
379
380 case Statement::Kind::kReturn:
381 // Returns are an early exit regardless of the surrounding control structures.
382 return fConditionalExits ? fInConditional : !fInConditional;
383
384 case Statement::Kind::kContinue:
385 // Continues are an early exit from switches, but not loops.
386 return !fInLoop &&
387 (fConditionalExits ? fInConditional : !fInConditional);
388
389 case Statement::Kind::kBreak:
390 // Breaks cannot escape from switches or loops.
391 return !fInLoop && !fInSwitch &&
392 (fConditionalExits ? fInConditional : !fInConditional);
393
394 case Statement::Kind::kIf: {
395 ++fInConditional;
396 bool result = INHERITED::visitStatement(stmt);
397 --fInConditional;
398 return result;
399 }
400
401 case Statement::Kind::kFor:
402 case Statement::Kind::kDo: {
403 // Loops are treated as conditionals because a loop could potentially execute zero
404 // times. We don't have a straightforward way to determine that a loop definitely
405 // executes at least once.
406 ++fInConditional;
407 ++fInLoop;
408 bool result = INHERITED::visitStatement(stmt);
409 --fInLoop;
410 --fInConditional;
411 return result;
412 }
413
414 case Statement::Kind::kSwitch: {
415 ++fInSwitch;
416 bool result = INHERITED::visitStatement(stmt);
417 --fInSwitch;
418 return result;
419 }
420
421 default:
422 return false;
423 }
424 }
425
426 bool fConditionalExits = false;
427 int fInConditional = 0;
428 int fInLoop = 0;
429 int fInSwitch = 0;
430 using INHERITED = ProgramVisitor;
431};
432
John Stilesb3dcbb12021-03-04 16:00:20 -0500433class ReturnsOnAllPathsVisitor : public ProgramVisitor {
434public:
435 bool visitExpression(const Expression& expr) override {
436 // We can avoid processing expressions entirely.
437 return false;
438 }
439
440 bool visitStatement(const Statement& stmt) override {
441 switch (stmt.kind()) {
442 // Returns, breaks, or continues will stop the scan, so only one of these should ever be
443 // true.
444 case Statement::Kind::kReturn:
445 fFoundReturn = true;
446 return true;
447
448 case Statement::Kind::kBreak:
449 fFoundBreak = true;
450 return true;
451
452 case Statement::Kind::kContinue:
453 fFoundContinue = true;
454 return true;
455
456 case Statement::Kind::kIf: {
457 const IfStatement& i = stmt.as<IfStatement>();
458 ReturnsOnAllPathsVisitor trueVisitor;
459 ReturnsOnAllPathsVisitor falseVisitor;
460 trueVisitor.visitStatement(*i.ifTrue());
461 if (i.ifFalse()) {
462 falseVisitor.visitStatement(*i.ifFalse());
463 }
464 // If either branch leads to a break or continue, we report the entire if as
465 // containing a break or continue, since we don't know which side will be reached.
466 fFoundBreak = (trueVisitor.fFoundBreak || falseVisitor.fFoundBreak);
467 fFoundContinue = (trueVisitor.fFoundContinue || falseVisitor.fFoundContinue);
468 // On the other hand, we only want to report returns that definitely happen, so we
469 // require those to be found on both sides.
470 fFoundReturn = (trueVisitor.fFoundReturn && falseVisitor.fFoundReturn);
471 return fFoundBreak || fFoundContinue || fFoundReturn;
472 }
473 case Statement::Kind::kFor: {
474 const ForStatement& f = stmt.as<ForStatement>();
475 // We assume a for/while loop runs for at least one iteration; this isn't strictly
476 // guaranteed, but it's better to be slightly over-permissive here than to fail on
477 // reasonable code.
478 ReturnsOnAllPathsVisitor forVisitor;
479 forVisitor.visitStatement(*f.statement());
480 // A for loop that contains a break or continue is safe; it won't exit the entire
481 // function, just the loop. So we disregard those signals.
482 fFoundReturn = forVisitor.fFoundReturn;
483 return fFoundReturn;
484 }
485 case Statement::Kind::kDo: {
486 const DoStatement& d = stmt.as<DoStatement>();
487 // Do-while blocks are always entered at least once.
488 ReturnsOnAllPathsVisitor doVisitor;
489 doVisitor.visitStatement(*d.statement());
490 // A do-while loop that contains a break or continue is safe; it won't exit the
491 // entire function, just the loop. So we disregard those signals.
492 fFoundReturn = doVisitor.fFoundReturn;
493 return fFoundReturn;
494 }
495 case Statement::Kind::kBlock:
496 // Blocks are definitely entered and don't imply any additional control flow.
497 // If the block contains a break, continue or return, we want to keep that.
498 return INHERITED::visitStatement(stmt);
499
500 case Statement::Kind::kSwitch: {
501 // Switches are the most complex control flow we need to deal with; fortunately we
502 // already have good primitives for dissecting them. We need to verify that:
503 // - a default case exists, so that every possible input value is covered
504 // - every switch-case either (a) returns unconditionally, or
505 // (b) falls through to another case that does
506 const SwitchStatement& s = stmt.as<SwitchStatement>();
507 bool foundDefault = false;
508 bool fellThrough = false;
John Stiles628777c2021-08-04 22:07:41 -0400509 for (const std::unique_ptr<Statement>& switchStmt : s.cases()) {
John Stilesb3dcbb12021-03-04 16:00:20 -0500510 // The default case is indicated by a null value. A switch without a default
511 // case cannot definitively return, as its value might not be in the cases list.
John Stiles628777c2021-08-04 22:07:41 -0400512 const SwitchCase& sc = switchStmt->as<SwitchCase>();
John Stilesb23a64b2021-03-11 08:27:59 -0500513 if (!sc.value()) {
John Stilesb3dcbb12021-03-04 16:00:20 -0500514 foundDefault = true;
515 }
516 // Scan this switch-case for any exit (break, continue or return).
517 ReturnsOnAllPathsVisitor caseVisitor;
John Stilesb23a64b2021-03-11 08:27:59 -0500518 caseVisitor.visitStatement(sc);
John Stilesb3dcbb12021-03-04 16:00:20 -0500519
520 // If we found a break or continue, whether conditional or not, this switch case
521 // can't be called an unconditional return. Switches absorb breaks but not
522 // continues.
523 if (caseVisitor.fFoundContinue) {
524 fFoundContinue = true;
525 return false;
526 }
527 if (caseVisitor.fFoundBreak) {
528 return false;
529 }
530 // We just confirmed that there weren't any breaks or continues. If we didn't
531 // find an unconditional return either, the switch is considered fallen-through.
532 // (There might be a conditional return, but that doesn't count.)
533 fellThrough = !caseVisitor.fFoundReturn;
534 }
535
536 // If we didn't find a default case, or the very last case fell through, this switch
537 // doesn't meet our criteria.
538 if (fellThrough || !foundDefault) {
539 return false;
540 }
541
542 // We scanned the entire switch, found a default case, and every section either fell
543 // through or contained an unconditional return.
544 fFoundReturn = true;
545 return true;
546 }
547
548 case Statement::Kind::kSwitchCase:
549 // Recurse into the switch-case.
550 return INHERITED::visitStatement(stmt);
551
552 case Statement::Kind::kDiscard:
553 case Statement::Kind::kExpression:
554 case Statement::Kind::kInlineMarker:
555 case Statement::Kind::kNop:
556 case Statement::Kind::kVarDeclaration:
557 // None of these statements could contain a return.
558 break;
559 }
560
561 return false;
562 }
563
564 bool fFoundReturn = false;
565 bool fFoundBreak = false;
566 bool fFoundContinue = false;
567
568 using INHERITED = ProgramVisitor;
569};
570
John Stilesa6841be2020-08-06 14:11:56 -0400571} // namespace
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400572
573////////////////////////////////////////////////////////////////////////////////
574// Analysis
575
Brian Osman4d571112021-04-27 09:10:10 -0400576SampleUsage Analysis::GetSampleUsage(const Program& program,
Brian Osman293497e2021-08-24 14:08:50 -0400577 const Variable& child,
Brian Osman8cdf28f2021-05-24 09:52:39 -0400578 bool writesToSampleCoords,
579 int* elidedSampleCoordCount) {
Brian Osman293497e2021-08-24 14:08:50 -0400580 MergeSampleUsageVisitor visitor(*program.fContext, child, writesToSampleCoords);
Brian Osman8cdf28f2021-05-24 09:52:39 -0400581 SampleUsage result = visitor.visit(program);
582 if (elidedSampleCoordCount) {
583 *elidedSampleCoordCount += visitor.elidedSampleCoordCount();
584 }
585 return result;
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400586}
587
Brian Osman92aac1e2020-08-05 16:48:58 -0400588bool Analysis::ReferencesBuiltin(const Program& program, int builtin) {
589 BuiltinVariableVisitor visitor(builtin);
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400590 return visitor.visit(program);
591}
592
Brian Osman92aac1e2020-08-05 16:48:58 -0400593bool Analysis::ReferencesSampleCoords(const Program& program) {
594 return Analysis::ReferencesBuiltin(program, SK_MAIN_COORDS_BUILTIN);
595}
596
597bool Analysis::ReferencesFragCoords(const Program& program) {
598 return Analysis::ReferencesBuiltin(program, SK_FRAGCOORD_BUILTIN);
599}
600
Brian Osman04d79fc2021-07-02 13:25:35 -0400601bool Analysis::CallsSampleOutsideMain(const Program& program) {
602 SampleOutsideMainVisitor visitor;
603 return visitor.visit(program);
604}
605
John Stiles61e5e202021-09-02 09:56:31 -0400606bool Analysis::CheckProgramUnrolledSize(const Program& program) {
607 // We check the size of strict-ES2 programs since SkVM will completely unroll them.
608 // Note that we *cannot* safely check the program size of non-ES2 code at this time, as it is
609 // allowed to do things we can't measure (e.g. the program can contain a recursive cycle). We
610 // could, at best, compute a lower bound.
611 const Context& context = *program.fContext;
612 SkASSERT(context.fConfig->strictES2Mode());
613
614 // If we decide that expressions are cheaper than statements, or that certain statements are
615 // more expensive than others, etc., we can always tweak these ratios as needed. A very rough
616 // ballpark estimate is currently good enough for our purposes.
617 static constexpr int kExpressionCost = 1;
618 static constexpr int kStatementCost = 1;
619 static constexpr int kUnknownCost = -1;
620 static constexpr int kProgramSizeLimit = 100000;
John Stiles2af4b132021-09-02 16:17:07 -0400621 static constexpr int kProgramStackDepthLimit = 50;
John Stiles61e5e202021-09-02 09:56:31 -0400622
623 class ProgramSizeVisitor : public ProgramVisitor {
624 public:
John Stiles6475b102021-09-02 14:09:23 -0400625 ProgramSizeVisitor(const Context& c) : fContext(c) {}
John Stiles61e5e202021-09-02 09:56:31 -0400626
627 using ProgramVisitor::visitProgramElement;
628
John Stiles6475b102021-09-02 14:09:23 -0400629 int functionSize() const {
630 return fFunctionSize;
631 }
632
633 bool visitProgramElement(const ProgramElement& pe) override {
634 if (pe.is<FunctionDefinition>()) {
635 // Check the function-size cache map first. We don't need to visit this function if
636 // we already processed it before.
637 const FunctionDeclaration* decl = &pe.as<FunctionDefinition>().declaration();
638 auto [iter, wasInserted] = fFunctionCostMap.insert({decl, kUnknownCost});
639 if (!wasInserted) {
640 // We already have this function in our map. We don't need to check it again.
641 if (iter->second == kUnknownCost) {
642 // If the function is present in the map with an unknown cost, we're
643 // recursively processing it--in other words, we found a cycle in the code.
John Stiles98ddea02021-09-02 14:33:08 -0400644 // Unwind our stack into a string.
645 String msg = "\n\t" + decl->description();
646 for (auto unwind = fStack.rbegin(); unwind != fStack.rend(); ++unwind) {
647 msg = "\n\t" + (*unwind)->description() + msg;
648 if (*unwind == decl) {
649 break;
650 }
651 }
652 msg = "potential recursion (function call cycle) not allowed:" + msg;
653 fContext.fErrors->error(pe.fOffset, std::move(msg));
John Stiles6475b102021-09-02 14:09:23 -0400654 fFunctionSize = iter->second = 0;
655 return true;
656 }
657 // Set the size to its known value.
658 fFunctionSize = iter->second;
659 return false;
660 }
661
John Stiles2af4b132021-09-02 16:17:07 -0400662 // If the function-call stack has gotten too deep, stop the analysis.
663 if (fStack.size() >= kProgramStackDepthLimit) {
664 String msg = "exceeded max function call depth:";
665 for (auto unwind = fStack.begin(); unwind != fStack.end(); ++unwind) {
666 msg += "\n\t" + (*unwind)->description();
667 }
668 msg += "\n\t" + decl->description();
669 fContext.fErrors->error(pe.fOffset, std::move(msg));
670 fFunctionSize = iter->second = 0;
671 return true;
672 }
673
John Stiles6475b102021-09-02 14:09:23 -0400674 // Calculate the function cost and store it in our cache.
John Stiles98ddea02021-09-02 14:33:08 -0400675 fStack.push_back(decl);
John Stiles6475b102021-09-02 14:09:23 -0400676 fFunctionSize = 0;
677 fUnrollFactor = 1;
678 bool result = INHERITED::visitProgramElement(pe);
679 iter->second = fFunctionSize;
John Stiles98ddea02021-09-02 14:33:08 -0400680 fStack.pop_back();
681
John Stiles6475b102021-09-02 14:09:23 -0400682 return result;
683 }
684
685 return INHERITED::visitProgramElement(pe);
John Stiles61e5e202021-09-02 09:56:31 -0400686 }
687
688 bool visitStatement(const Statement& stmt) override {
689 switch (stmt.kind()) {
690 case Statement::Kind::kFor: {
691 // We count a for-loop's unrolled size here. We expect that the init statement
692 // will be emitted once, and the next-expr and statement will be repeated in the
693 // output for every iteration of the loop. The test-expr is optimized away
694 // during the unroll and is not counted at all.
695 const ForStatement& forStmt = stmt.as<ForStatement>();
696 bool result = INHERITED::visitStatement(*forStmt.initializer());
697
698 int originalUnrollFactor = fUnrollFactor;
699
700 if (const LoopUnrollInfo* unrollInfo = forStmt.unrollInfo()) {
701 fUnrollFactor = SkSafeMath::Mul(fUnrollFactor, unrollInfo->fCount);
702 } else {
703 SkDEBUGFAIL("for-loops should always have unroll info in an ES2 program");
704 }
705
706 result = INHERITED::visitExpression(*forStmt.next()) ||
707 INHERITED::visitStatement(*forStmt.statement()) || result;
708
709 fUnrollFactor = originalUnrollFactor;
710 return result;
711 }
712
713 case Statement::Kind::kExpression:
714 // The cost of an expression-statement is counted in visitExpression. It would
715 // be double-dipping to count it here too.
716 break;
717
718 case Statement::Kind::kInlineMarker:
719 case Statement::Kind::kNop:
720 case Statement::Kind::kVarDeclaration:
721 // These statements don't directly consume any space in a compiled program.
722 break;
723
724 case Statement::Kind::kDo:
725 case Statement::Kind::kSwitch:
726 case Statement::Kind::kSwitchCase:
727 SkDEBUGFAIL("encountered a statement that shouldn't exist in an ES2 program");
728 break;
729
730 default:
John Stiles6475b102021-09-02 14:09:23 -0400731 fFunctionSize += fUnrollFactor * kStatementCost;
John Stiles61e5e202021-09-02 09:56:31 -0400732 break;
733 }
734
735 return INHERITED::visitStatement(stmt);
736 }
737
738 bool visitExpression(const Expression& expr) override {
739 // Other than function calls, all expressions are assumed to have a fixed unit cost.
John Stiles6475b102021-09-02 14:09:23 -0400740 bool earlyExit = false;
John Stiles61e5e202021-09-02 09:56:31 -0400741 int expressionCost = kExpressionCost;
742
743 if (expr.is<FunctionCall>()) {
John Stiles6475b102021-09-02 14:09:23 -0400744 // Visit this function call to calculate its size. If we've already sized it, this
745 // will retrieve the size from our cache.
John Stiles61e5e202021-09-02 09:56:31 -0400746 const FunctionCall& call = expr.as<FunctionCall>();
747 const FunctionDeclaration* decl = &call.function();
John Stiles61e5e202021-09-02 09:56:31 -0400748 if (decl->definition() && !decl->isIntrinsic()) {
John Stiles6475b102021-09-02 14:09:23 -0400749 int originalFunctionSize = fFunctionSize;
750 int originalUnrollFactor = fUnrollFactor;
John Stiles61e5e202021-09-02 09:56:31 -0400751
John Stiles6475b102021-09-02 14:09:23 -0400752 earlyExit = this->visitProgramElement(*decl->definition());
753 expressionCost = fFunctionSize;
John Stiles61e5e202021-09-02 09:56:31 -0400754
John Stiles6475b102021-09-02 14:09:23 -0400755 fFunctionSize = originalFunctionSize;
756 fUnrollFactor = originalUnrollFactor;
John Stiles61e5e202021-09-02 09:56:31 -0400757 }
758 }
759
John Stiles6475b102021-09-02 14:09:23 -0400760 fFunctionSize += fUnrollFactor * expressionCost;
761 return earlyExit || INHERITED::visitExpression(expr);
John Stiles61e5e202021-09-02 09:56:31 -0400762 }
763
764 private:
765 using INHERITED = ProgramVisitor;
766
John Stiles6475b102021-09-02 14:09:23 -0400767 [[maybe_unused]] const Context& fContext;
768 int fFunctionSize;
769 int fUnrollFactor;
John Stiles61e5e202021-09-02 09:56:31 -0400770 std::unordered_map<const FunctionDeclaration*, int> fFunctionCostMap;
John Stiles98ddea02021-09-02 14:33:08 -0400771 std::vector<const FunctionDeclaration*> fStack;
John Stiles61e5e202021-09-02 09:56:31 -0400772 };
773
John Stiles6475b102021-09-02 14:09:23 -0400774 // Process every function in our program.
775 ProgramSizeVisitor visitor{context};
John Stiles61e5e202021-09-02 09:56:31 -0400776 for (const std::unique_ptr<ProgramElement>& element : program.ownedElements()) {
John Stiles6475b102021-09-02 14:09:23 -0400777 if (element->is<FunctionDefinition>()) {
778 // Visit every function--we want to detect static recursion and report it as an error,
779 // even in unreferenced functions.
John Stiles61e5e202021-09-02 09:56:31 -0400780 visitor.visitProgramElement(*element);
John Stiles6475b102021-09-02 14:09:23 -0400781 // Report an error when main()'s flattened size is larger than our program limit.
782 if (visitor.functionSize() > kProgramSizeLimit &&
783 element->as<FunctionDefinition>().declaration().isMain()) {
784 context.fErrors->error(/*offset=*/-1, "program is too large");
785 }
John Stiles61e5e202021-09-02 09:56:31 -0400786 }
787 }
788
John Stiles61e5e202021-09-02 09:56:31 -0400789 return true;
790}
791
Ethan Nicholas98eae1e2021-09-01 14:37:29 -0400792bool Analysis::DetectVarDeclarationWithoutScope(const Statement& stmt, ErrorReporter* errors) {
793 // A variable declaration can create either a lone VarDeclaration or an unscoped Block
794 // containing multiple VarDeclaration statements. We need to detect either case.
795 const Variable* var;
796 if (stmt.is<VarDeclaration>()) {
797 // The single-variable case. No blocks at all.
798 var = &stmt.as<VarDeclaration>().var();
799 } else if (stmt.is<Block>()) {
800 // The multiple-variable case: an unscoped, non-empty block...
801 const Block& block = stmt.as<Block>();
802 if (block.isScope() || block.children().empty()) {
803 return false;
804 }
805 // ... holding a variable declaration.
806 const Statement& innerStmt = *block.children().front();
807 if (!innerStmt.is<VarDeclaration>()) {
808 return false;
809 }
810 var = &innerStmt.as<VarDeclaration>().var();
811 } else {
812 // This statement wasn't a variable declaration. No problem.
813 return false;
814 }
815
816 // Report an error.
817 SkASSERT(var);
818 if (errors) {
819 errors->error(stmt.fOffset, "variable '" + var->name() + "' must be created in a scope");
820 }
821 return true;
822}
823
John Stiles9b9415e2020-11-23 14:48:06 -0500824int Analysis::NodeCountUpToLimit(const FunctionDefinition& function, int limit) {
825 return NodeCountVisitor{limit}.visit(*function.body());
Ethan Nicholas6e0fa402020-08-20 14:08:23 -0400826}
827
John Stiles642cde22021-02-23 14:57:01 -0500828bool Analysis::SwitchCaseContainsUnconditionalExit(Statement& stmt) {
829 return SwitchCaseContainsExit{/*conditionalExits=*/false}.visitStatement(stmt);
830}
831
832bool Analysis::SwitchCaseContainsConditionalExit(Statement& stmt) {
833 return SwitchCaseContainsExit{/*conditionalExits=*/true}.visitStatement(stmt);
834}
835
Brian Osman010ce6a2020-10-19 16:34:10 -0400836std::unique_ptr<ProgramUsage> Analysis::GetUsage(const Program& program) {
837 auto usage = std::make_unique<ProgramUsage>();
838 ProgramUsageVisitor addRefs(usage.get(), /*delta=*/+1);
839 addRefs.visit(program);
840 return usage;
841}
842
Brian Osman0006ad02020-11-18 15:38:39 -0500843std::unique_ptr<ProgramUsage> Analysis::GetUsage(const LoadedModule& module) {
844 auto usage = std::make_unique<ProgramUsage>();
845 ProgramUsageVisitor addRefs(usage.get(), /*delta=*/+1);
846 for (const auto& element : module.fElements) {
847 addRefs.visitProgramElement(*element);
848 }
849 return usage;
850}
851
Brian Osman010ce6a2020-10-19 16:34:10 -0400852ProgramUsage::VariableCounts ProgramUsage::get(const Variable& v) const {
John Stiles04a8a542021-03-10 19:03:26 -0500853 const VariableCounts* counts = fVariableCounts.find(&v);
854 SkASSERT(counts);
855 return *counts;
Brian Osman010ce6a2020-10-19 16:34:10 -0400856}
857
858bool ProgramUsage::isDead(const Variable& v) const {
859 const Modifiers& modifiers = v.modifiers();
860 VariableCounts counts = this->get(v);
861 if ((v.storage() != Variable::Storage::kLocal && counts.fRead) ||
Brian Osmane49703f2021-04-19 11:15:24 -0400862 (modifiers.fFlags &
863 (Modifiers::kIn_Flag | Modifiers::kOut_Flag | Modifiers::kUniform_Flag))) {
Brian Osman010ce6a2020-10-19 16:34:10 -0400864 return false;
865 }
John Stilesf10eff32021-03-16 10:57:55 -0400866 // Consider the variable dead if it's never read and never written (besides the initial-value).
867 return !counts.fRead && (counts.fWrite <= (v.initialValue() ? 1 : 0));
Brian Osman010ce6a2020-10-19 16:34:10 -0400868}
869
870int ProgramUsage::get(const FunctionDeclaration& f) const {
871 const int* count = fCallCounts.find(&f);
872 return count ? *count : 0;
873}
874
John Stiles60dbf072021-08-02 14:22:34 -0400875void ProgramUsage::add(const Expression* expr) {
876 ProgramUsageVisitor addRefs(this, /*delta=*/+1);
877 addRefs.visitExpression(*expr);
Brian Osman010ce6a2020-10-19 16:34:10 -0400878}
879
880void ProgramUsage::add(const Statement* stmt) {
881 ProgramUsageVisitor addRefs(this, /*delta=*/+1);
882 addRefs.visitStatement(*stmt);
883}
884
John Stiles60dbf072021-08-02 14:22:34 -0400885void ProgramUsage::add(const ProgramElement& element) {
886 ProgramUsageVisitor addRefs(this, /*delta=*/+1);
887 addRefs.visitProgramElement(element);
888}
889
Brian Osman010ce6a2020-10-19 16:34:10 -0400890void ProgramUsage::remove(const Expression* expr) {
891 ProgramUsageVisitor subRefs(this, /*delta=*/-1);
892 subRefs.visitExpression(*expr);
893}
894
895void ProgramUsage::remove(const Statement* stmt) {
896 ProgramUsageVisitor subRefs(this, /*delta=*/-1);
897 subRefs.visitStatement(*stmt);
898}
899
900void ProgramUsage::remove(const ProgramElement& element) {
901 ProgramUsageVisitor subRefs(this, /*delta=*/-1);
902 subRefs.visitProgramElement(element);
Brian Osman2e25ff42020-10-15 10:32:04 -0400903}
904
Ethan Nicholas765d2fe2020-08-26 08:29:55 -0400905bool Analysis::StatementWritesToVariable(const Statement& stmt, const Variable& var) {
906 return VariableWriteVisitor(&var).visit(stmt);
907}
908
John Stilesb21fac22020-12-04 15:36:49 -0500909bool Analysis::IsAssignable(Expression& expr, AssignmentInfo* info, ErrorReporter* errors) {
John Stilesa976da72020-09-25 23:06:26 -0400910 TrivialErrorReporter trivialErrors;
John Stilesb21fac22020-12-04 15:36:49 -0500911 return IsAssignableVisitor{errors ? errors : &trivialErrors}.visit(expr, info);
John Stilesdce4d3e2020-09-25 14:35:13 -0400912}
913
John Stilesbb8cf582021-08-26 23:34:59 -0400914bool Analysis::UpdateVariableRefKind(Expression* expr,
915 VariableReference::RefKind kind,
916 ErrorReporter* errors) {
John Stiles516704b2021-02-26 15:01:57 -0500917 Analysis::AssignmentInfo info;
918 if (!Analysis::IsAssignable(*expr, &info, errors)) {
919 return false;
920 }
921 if (!info.fAssignedVar) {
John Stilesbb8cf582021-08-26 23:34:59 -0400922 if (errors) {
923 errors->error(expr->fOffset, "can't assign to expression '" +
924 expr->description() + "'");
925 }
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) {
933 return expr.is<IntLiteral>() ||
934 expr.is<FloatLiteral>() ||
935 expr.is<BoolLiteral>() ||
936 expr.is<VariableReference>() ||
937 (expr.is<Swizzle>() &&
938 IsTrivialExpression(*expr.as<Swizzle>().base())) ||
939 (expr.is<FieldAccess>() &&
940 IsTrivialExpression(*expr.as<FieldAccess>().base())) ||
John Stiles2938eea2021-04-01 18:58:25 -0400941 (expr.isAnyConstructor() &&
942 expr.asAnyConstructor().argumentSpan().size() == 1 &&
943 IsTrivialExpression(*expr.asAnyConstructor().argumentSpan().front())) ||
944 (expr.isAnyConstructor() &&
John Stilesc30fbca2020-11-19 16:25:49 -0500945 expr.isConstantOrUniform()) ||
946 (expr.is<IndexExpression>() &&
947 expr.as<IndexExpression>().index()->is<IntLiteral>() &&
948 IsTrivialExpression(*expr.as<IndexExpression>().base()));
949}
950
John Stiles5676c572021-03-08 17:10:52 -0500951bool Analysis::IsSameExpressionTree(const Expression& left, const Expression& right) {
John Stiles95d0bad2021-03-01 17:02:28 -0500952 if (left.kind() != right.kind() || left.type() != right.type()) {
953 return false;
954 }
955
John Stiles5676c572021-03-08 17:10:52 -0500956 // This isn't a fully exhaustive list of expressions by any stretch of the imagination; for
957 // instance, `x[y+1] = x[y+1]` isn't detected because we don't look at BinaryExpressions.
958 // Since this is intended to be used for optimization purposes, handling the common cases is
959 // sufficient.
John Stiles95d0bad2021-03-01 17:02:28 -0500960 switch (left.kind()) {
961 case Expression::Kind::kIntLiteral:
962 return left.as<IntLiteral>().value() == right.as<IntLiteral>().value();
963
John Stiles5676c572021-03-08 17:10:52 -0500964 case Expression::Kind::kFloatLiteral:
965 return left.as<FloatLiteral>().value() == right.as<FloatLiteral>().value();
966
967 case Expression::Kind::kBoolLiteral:
968 return left.as<BoolLiteral>().value() == right.as<BoolLiteral>().value();
969
John Stiles7384b372021-04-01 13:48:15 -0400970 case Expression::Kind::kConstructorArray:
John Stilese3ae9682021-08-05 10:35:01 -0400971 case Expression::Kind::kConstructorArrayCast:
John Stiles8cad6372021-04-07 12:31:13 -0400972 case Expression::Kind::kConstructorCompound:
973 case Expression::Kind::kConstructorCompoundCast:
John Stiles2938eea2021-04-01 18:58:25 -0400974 case Expression::Kind::kConstructorDiagonalMatrix:
John Stiles5abb9e12021-04-06 13:47:19 -0400975 case Expression::Kind::kConstructorMatrixResize:
John Stilesfd7252f2021-04-04 22:24:40 -0400976 case Expression::Kind::kConstructorScalarCast:
John Stilesd47330f2021-04-08 23:25:52 -0400977 case Expression::Kind::kConstructorStruct:
John Stiles268a73f2021-04-07 12:30:22 -0400978 case Expression::Kind::kConstructorSplat: {
John Stilesfd7252f2021-04-04 22:24:40 -0400979 if (left.kind() != right.kind()) {
980 return false;
981 }
John Stiles7384b372021-04-01 13:48:15 -0400982 const AnyConstructor& leftCtor = left.asAnyConstructor();
983 const AnyConstructor& rightCtor = right.asAnyConstructor();
984 const auto leftSpan = leftCtor.argumentSpan();
985 const auto rightSpan = rightCtor.argumentSpan();
986 if (leftSpan.size() != rightSpan.size()) {
John Stiles5676c572021-03-08 17:10:52 -0500987 return false;
988 }
John Stiles7384b372021-04-01 13:48:15 -0400989 for (size_t index = 0; index < leftSpan.size(); ++index) {
990 if (!IsSameExpressionTree(*leftSpan[index], *rightSpan[index])) {
John Stiles5676c572021-03-08 17:10:52 -0500991 return false;
992 }
993 }
994 return true;
995 }
John Stiles95d0bad2021-03-01 17:02:28 -0500996 case Expression::Kind::kFieldAccess:
997 return left.as<FieldAccess>().fieldIndex() == right.as<FieldAccess>().fieldIndex() &&
John Stiles5676c572021-03-08 17:10:52 -0500998 IsSameExpressionTree(*left.as<FieldAccess>().base(),
999 *right.as<FieldAccess>().base());
John Stiles95d0bad2021-03-01 17:02:28 -05001000
1001 case Expression::Kind::kIndex:
John Stiles5676c572021-03-08 17:10:52 -05001002 return IsSameExpressionTree(*left.as<IndexExpression>().index(),
1003 *right.as<IndexExpression>().index()) &&
1004 IsSameExpressionTree(*left.as<IndexExpression>().base(),
1005 *right.as<IndexExpression>().base());
John Stiles95d0bad2021-03-01 17:02:28 -05001006
1007 case Expression::Kind::kSwizzle:
1008 return left.as<Swizzle>().components() == right.as<Swizzle>().components() &&
John Stiles5676c572021-03-08 17:10:52 -05001009 IsSameExpressionTree(*left.as<Swizzle>().base(), *right.as<Swizzle>().base());
John Stiles95d0bad2021-03-01 17:02:28 -05001010
1011 case Expression::Kind::kVariableReference:
1012 return left.as<VariableReference>().variable() ==
1013 right.as<VariableReference>().variable();
1014
1015 default:
1016 return false;
1017 }
1018}
1019
John Stilesd80cef62021-03-29 11:22:43 -04001020static bool get_constant_value(const Expression& expr, double* val) {
John Stiles21a50ec2021-04-06 14:49:36 -04001021 const Expression* valExpr = expr.getConstantSubexpression(0);
1022 if (!valExpr) {
John Stilesd80cef62021-03-29 11:22:43 -04001023 return false;
1024 }
John Stiles21a50ec2021-04-06 14:49:36 -04001025 if (valExpr->is<IntLiteral>()) {
1026 *val = static_cast<double>(valExpr->as<IntLiteral>().value());
1027 return true;
John Stilesd80cef62021-03-29 11:22:43 -04001028 }
John Stiles21a50ec2021-04-06 14:49:36 -04001029 if (valExpr->is<FloatLiteral>()) {
1030 *val = static_cast<double>(valExpr->as<FloatLiteral>().value());
1031 return true;
1032 }
1033 SkDEBUGFAILF("unexpected constant type (%s)", expr.type().description().c_str());
1034 return false;
John Stilesd80cef62021-03-29 11:22:43 -04001035}
1036
John Stiles232b4ce2021-03-01 22:14:22 -05001037static const char* invalid_for_ES2(int offset,
1038 const Statement* loopInitializer,
1039 const Expression* loopTest,
1040 const Expression* loopNext,
1041 const Statement* loopStatement,
John Stiles9c975c52021-08-31 10:18:57 -04001042 LoopUnrollInfo& loopInfo) {
Brian Osman77ba8102021-01-12 17:15:30 -05001043 //
1044 // init_declaration has the form: type_specifier identifier = constant_expression
1045 //
John Stiles232b4ce2021-03-01 22:14:22 -05001046 if (!loopInitializer) {
Brian Osman77ba8102021-01-12 17:15:30 -05001047 return "missing init declaration";
1048 }
John Stiles232b4ce2021-03-01 22:14:22 -05001049 if (!loopInitializer->is<VarDeclaration>()) {
Brian Osman77ba8102021-01-12 17:15:30 -05001050 return "invalid init declaration";
1051 }
John Stiles232b4ce2021-03-01 22:14:22 -05001052 const VarDeclaration& initDecl = loopInitializer->as<VarDeclaration>();
Brian Osman6c7910e2021-01-14 09:50:52 -05001053 if (!initDecl.baseType().isNumber()) {
Brian Osman77ba8102021-01-12 17:15:30 -05001054 return "invalid type for loop index";
1055 }
1056 if (initDecl.arraySize() != 0) {
1057 return "invalid type for loop index";
1058 }
1059 if (!initDecl.value()) {
1060 return "missing loop index initializer";
1061 }
John Stilesd80cef62021-03-29 11:22:43 -04001062 if (!get_constant_value(*initDecl.value(), &loopInfo.fStart)) {
Brian Osman77ba8102021-01-12 17:15:30 -05001063 return "loop index initializer must be a constant expression";
1064 }
1065
1066 loopInfo.fIndex = &initDecl.var();
1067
1068 auto is_loop_index = [&](const std::unique_ptr<Expression>& expr) {
1069 return expr->is<VariableReference>() &&
1070 expr->as<VariableReference>().variable() == loopInfo.fIndex;
1071 };
1072
1073 //
1074 // condition has the form: loop_index relational_operator constant_expression
1075 //
John Stiles232b4ce2021-03-01 22:14:22 -05001076 if (!loopTest) {
Brian Osman77ba8102021-01-12 17:15:30 -05001077 return "missing condition";
1078 }
John Stiles232b4ce2021-03-01 22:14:22 -05001079 if (!loopTest->is<BinaryExpression>()) {
Brian Osman77ba8102021-01-12 17:15:30 -05001080 return "invalid condition";
1081 }
John Stiles232b4ce2021-03-01 22:14:22 -05001082 const BinaryExpression& cond = loopTest->as<BinaryExpression>();
Brian Osman77ba8102021-01-12 17:15:30 -05001083 if (!is_loop_index(cond.left())) {
1084 return "expected loop index on left hand side of condition";
1085 }
1086 // relational_operator is one of: > >= < <= == or !=
John Stiles45990502021-02-16 10:55:27 -05001087 switch (cond.getOperator().kind()) {
Brian Osman77ba8102021-01-12 17:15:30 -05001088 case Token::Kind::TK_GT:
1089 case Token::Kind::TK_GTEQ:
1090 case Token::Kind::TK_LT:
1091 case Token::Kind::TK_LTEQ:
1092 case Token::Kind::TK_EQEQ:
1093 case Token::Kind::TK_NEQ:
1094 break;
1095 default:
1096 return "invalid relational operator";
1097 }
1098 double loopEnd = 0;
John Stilesd80cef62021-03-29 11:22:43 -04001099 if (!get_constant_value(*cond.right(), &loopEnd)) {
Brian Osman77ba8102021-01-12 17:15:30 -05001100 return "loop index must be compared with a constant expression";
1101 }
1102
1103 //
1104 // expression has one of the following forms:
1105 // loop_index++
1106 // loop_index--
1107 // loop_index += constant_expression
1108 // loop_index -= constant_expression
1109 // The spec doesn't mention prefix increment and decrement, but there is some consensus that
1110 // it's an oversight, so we allow those as well.
1111 //
John Stiles232b4ce2021-03-01 22:14:22 -05001112 if (!loopNext) {
Brian Osman77ba8102021-01-12 17:15:30 -05001113 return "missing loop expression";
1114 }
John Stiles232b4ce2021-03-01 22:14:22 -05001115 switch (loopNext->kind()) {
Brian Osman77ba8102021-01-12 17:15:30 -05001116 case Expression::Kind::kBinary: {
John Stiles232b4ce2021-03-01 22:14:22 -05001117 const BinaryExpression& next = loopNext->as<BinaryExpression>();
Brian Osman77ba8102021-01-12 17:15:30 -05001118 if (!is_loop_index(next.left())) {
1119 return "expected loop index in loop expression";
1120 }
John Stilesd80cef62021-03-29 11:22:43 -04001121 if (!get_constant_value(*next.right(), &loopInfo.fDelta)) {
Brian Osman77ba8102021-01-12 17:15:30 -05001122 return "loop index must be modified by a constant expression";
1123 }
John Stiles45990502021-02-16 10:55:27 -05001124 switch (next.getOperator().kind()) {
Brian Osman77ba8102021-01-12 17:15:30 -05001125 case Token::Kind::TK_PLUSEQ: break;
1126 case Token::Kind::TK_MINUSEQ: loopInfo.fDelta = -loopInfo.fDelta; break;
1127 default:
1128 return "invalid operator in loop expression";
1129 }
1130 } break;
1131 case Expression::Kind::kPrefix: {
John Stiles232b4ce2021-03-01 22:14:22 -05001132 const PrefixExpression& next = loopNext->as<PrefixExpression>();
Brian Osman77ba8102021-01-12 17:15:30 -05001133 if (!is_loop_index(next.operand())) {
1134 return "expected loop index in loop expression";
1135 }
John Stiles45990502021-02-16 10:55:27 -05001136 switch (next.getOperator().kind()) {
Brian Osman77ba8102021-01-12 17:15:30 -05001137 case Token::Kind::TK_PLUSPLUS: loopInfo.fDelta = 1; break;
1138 case Token::Kind::TK_MINUSMINUS: loopInfo.fDelta = -1; break;
1139 default:
1140 return "invalid operator in loop expression";
1141 }
1142 } break;
1143 case Expression::Kind::kPostfix: {
John Stiles232b4ce2021-03-01 22:14:22 -05001144 const PostfixExpression& next = loopNext->as<PostfixExpression>();
Brian Osman77ba8102021-01-12 17:15:30 -05001145 if (!is_loop_index(next.operand())) {
1146 return "expected loop index in loop expression";
1147 }
John Stiles45990502021-02-16 10:55:27 -05001148 switch (next.getOperator().kind()) {
Brian Osman77ba8102021-01-12 17:15:30 -05001149 case Token::Kind::TK_PLUSPLUS: loopInfo.fDelta = 1; break;
1150 case Token::Kind::TK_MINUSMINUS: loopInfo.fDelta = -1; break;
1151 default:
1152 return "invalid operator in loop expression";
1153 }
1154 } break;
1155 default:
1156 return "invalid loop expression";
1157 }
1158
1159 //
1160 // Within the body of the loop, the loop index is not statically assigned to, nor is it used as
1161 // argument to a function 'out' or 'inout' parameter.
1162 //
John Stiles232b4ce2021-03-01 22:14:22 -05001163 if (Analysis::StatementWritesToVariable(*loopStatement, initDecl.var())) {
Brian Osman77ba8102021-01-12 17:15:30 -05001164 return "loop index must not be modified within body of the loop";
1165 }
1166
1167 // Finally, compute the iteration count, based on the bounds, and the termination operator.
1168 constexpr int kMaxUnrollableLoopLength = 128;
1169 loopInfo.fCount = 0;
1170
1171 double val = loopInfo.fStart;
1172 auto evalCond = [&]() {
John Stiles45990502021-02-16 10:55:27 -05001173 switch (cond.getOperator().kind()) {
Brian Osman77ba8102021-01-12 17:15:30 -05001174 case Token::Kind::TK_GT: return val > loopEnd;
1175 case Token::Kind::TK_GTEQ: return val >= loopEnd;
1176 case Token::Kind::TK_LT: return val < loopEnd;
1177 case Token::Kind::TK_LTEQ: return val <= loopEnd;
1178 case Token::Kind::TK_EQEQ: return val == loopEnd;
1179 case Token::Kind::TK_NEQ: return val != loopEnd;
1180 default: SkUNREACHABLE;
1181 }
1182 };
1183
1184 for (loopInfo.fCount = 0; loopInfo.fCount <= kMaxUnrollableLoopLength; ++loopInfo.fCount) {
1185 if (!evalCond()) {
1186 break;
1187 }
1188 val += loopInfo.fDelta;
1189 }
1190
1191 if (loopInfo.fCount > kMaxUnrollableLoopLength) {
1192 return "loop must guarantee termination in fewer iterations";
1193 }
1194
1195 return nullptr; // All checks pass
1196}
1197
John Stiles9c975c52021-08-31 10:18:57 -04001198std::unique_ptr<LoopUnrollInfo> Analysis::GetLoopUnrollInfo(int offset,
1199 const Statement* loopInitializer,
1200 const Expression* loopTest,
1201 const Expression* loopNext,
1202 const Statement* loopStatement,
1203 ErrorReporter* errors) {
1204 auto result = std::make_unique<LoopUnrollInfo>();
1205 if (const char* msg = invalid_for_ES2(offset, loopInitializer, loopTest, loopNext,
1206 loopStatement, *result)) {
1207 result = nullptr;
Brian Osman77ba8102021-01-12 17:15:30 -05001208 if (errors) {
John Stiles232b4ce2021-03-01 22:14:22 -05001209 errors->error(offset, msg);
Brian Osman77ba8102021-01-12 17:15:30 -05001210 }
Brian Osman77ba8102021-01-12 17:15:30 -05001211 }
John Stiles9c975c52021-08-31 10:18:57 -04001212 return result;
Brian Osman77ba8102021-01-12 17:15:30 -05001213}
1214
Brian Osman7b361492021-02-25 11:25:30 -05001215// Checks for ES2 constant-expression rules, and (optionally) constant-index-expression rules
1216// (if loopIndices is non-nullptr)
1217class ConstantExpressionVisitor : public ProgramVisitor {
Brian Osmanea485e52021-01-15 13:20:32 -05001218public:
Brian Osman7b361492021-02-25 11:25:30 -05001219 ConstantExpressionVisitor(const std::set<const Variable*>* loopIndices)
Brian Osmanea485e52021-01-15 13:20:32 -05001220 : fLoopIndices(loopIndices) {}
1221
1222 bool visitExpression(const Expression& e) override {
1223 // A constant-(index)-expression is one of...
1224 switch (e.kind()) {
1225 // ... a literal value
1226 case Expression::Kind::kBoolLiteral:
1227 case Expression::Kind::kIntLiteral:
1228 case Expression::Kind::kFloatLiteral:
1229 return false;
1230
John Stiles532138c2021-03-04 16:29:22 -05001231 // ... settings can appear in fragment processors; they will resolve when compiled
1232 case Expression::Kind::kSetting:
1233 return false;
1234
Brian Osman7b361492021-02-25 11:25:30 -05001235 // ... a global or local variable qualified as 'const', excluding function parameters.
1236 // ... loop indices as defined in section 4. [constant-index-expression]
1237 case Expression::Kind::kVariableReference: {
1238 const Variable* v = e.as<VariableReference>().variable();
1239 if ((v->storage() == Variable::Storage::kGlobal ||
1240 v->storage() == Variable::Storage::kLocal) &&
1241 (v->modifiers().fFlags & Modifiers::kConst_Flag)) {
1242 return false;
1243 }
1244 return !fLoopIndices || fLoopIndices->find(v) == fLoopIndices->end();
1245 }
Brian Osmanea485e52021-01-15 13:20:32 -05001246
1247 // ... expressions composed of both of the above
1248 case Expression::Kind::kBinary:
John Stiles7384b372021-04-01 13:48:15 -04001249 case Expression::Kind::kConstructorArray:
John Stilese3ae9682021-08-05 10:35:01 -04001250 case Expression::Kind::kConstructorArrayCast:
John Stiles8cad6372021-04-07 12:31:13 -04001251 case Expression::Kind::kConstructorCompound:
1252 case Expression::Kind::kConstructorCompoundCast:
John Stilese1182782021-03-30 22:09:37 -04001253 case Expression::Kind::kConstructorDiagonalMatrix:
John Stiles5abb9e12021-04-06 13:47:19 -04001254 case Expression::Kind::kConstructorMatrixResize:
John Stilesfd7252f2021-04-04 22:24:40 -04001255 case Expression::Kind::kConstructorScalarCast:
John Stiles2938eea2021-04-01 18:58:25 -04001256 case Expression::Kind::kConstructorSplat:
John Stilesd47330f2021-04-08 23:25:52 -04001257 case Expression::Kind::kConstructorStruct:
Brian Osmanea485e52021-01-15 13:20:32 -05001258 case Expression::Kind::kFieldAccess:
1259 case Expression::Kind::kIndex:
1260 case Expression::Kind::kPrefix:
1261 case Expression::Kind::kPostfix:
1262 case Expression::Kind::kSwizzle:
1263 case Expression::Kind::kTernary:
1264 return INHERITED::visitExpression(e);
1265
John Stiles7bd3f1c2021-08-27 16:12:10 -04001266 // Function calls are completely disallowed in SkSL constant-(index)-expressions.
1267 // GLSL does mandate that calling a built-in function where the arguments are all
1268 // constant-expressions should result in a constant-expression. SkSL handles this by
1269 // optimizing fully-constant function calls into literals in FunctionCall::Make.
Brian Osmanea485e52021-01-15 13:20:32 -05001270 case Expression::Kind::kFunctionCall:
John Stiles7bd3f1c2021-08-27 16:12:10 -04001271 case Expression::Kind::kExternalFunctionCall:
1272 case Expression::Kind::kChildCall:
Brian Osmanea485e52021-01-15 13:20:32 -05001273
John Stiles7bd3f1c2021-08-27 16:12:10 -04001274 // These shouldn't appear in a valid program at all, and definitely aren't
1275 // constant-index-expressions.
Ethan Nicholas549c6b82021-06-25 12:31:44 -04001276 case Expression::Kind::kPoison:
John Stiles7bd3f1c2021-08-27 16:12:10 -04001277 case Expression::Kind::kFunctionReference:
1278 case Expression::Kind::kExternalFunctionReference:
Brian Osman3099f792021-09-01 13:12:16 -04001279 case Expression::Kind::kMethodReference:
John Stiles7bd3f1c2021-08-27 16:12:10 -04001280 case Expression::Kind::kTypeReference:
1281 case Expression::Kind::kCodeString:
Ethan Nicholas549c6b82021-06-25 12:31:44 -04001282 return true;
1283
Brian Osmanea485e52021-01-15 13:20:32 -05001284 default:
1285 SkDEBUGFAIL("Unexpected expression type");
1286 return true;
1287 }
1288 }
1289
1290private:
1291 const std::set<const Variable*>* fLoopIndices;
1292 using INHERITED = ProgramVisitor;
1293};
1294
1295class ES2IndexingVisitor : public ProgramVisitor {
1296public:
1297 ES2IndexingVisitor(ErrorReporter& errors) : fErrors(errors) {}
1298
1299 bool visitStatement(const Statement& s) override {
1300 if (s.is<ForStatement>()) {
1301 const ForStatement& f = s.as<ForStatement>();
1302 SkASSERT(f.initializer() && f.initializer()->is<VarDeclaration>());
1303 const Variable* var = &f.initializer()->as<VarDeclaration>().var();
1304 auto [iter, inserted] = fLoopIndices.insert(var);
1305 SkASSERT(inserted);
1306 bool result = this->visitStatement(*f.statement());
1307 fLoopIndices.erase(iter);
1308 return result;
1309 }
1310 return INHERITED::visitStatement(s);
1311 }
1312
1313 bool visitExpression(const Expression& e) override {
1314 if (e.is<IndexExpression>()) {
1315 const IndexExpression& i = e.as<IndexExpression>();
Brian Osman7b361492021-02-25 11:25:30 -05001316 ConstantExpressionVisitor indexerInvalid(&fLoopIndices);
Brian Osmanea485e52021-01-15 13:20:32 -05001317 if (indexerInvalid.visitExpression(*i.index())) {
1318 fErrors.error(i.fOffset, "index expression must be constant");
1319 return true;
1320 }
1321 }
1322 return INHERITED::visitExpression(e);
1323 }
1324
1325 using ProgramVisitor::visitProgramElement;
1326
1327private:
1328 ErrorReporter& fErrors;
1329 std::set<const Variable*> fLoopIndices;
1330 using INHERITED = ProgramVisitor;
1331};
1332
1333
1334void Analysis::ValidateIndexingForES2(const ProgramElement& pe, ErrorReporter& errors) {
1335 ES2IndexingVisitor visitor(errors);
1336 visitor.visitProgramElement(pe);
1337}
1338
Brian Osman7b361492021-02-25 11:25:30 -05001339bool Analysis::IsConstantExpression(const Expression& expr) {
1340 ConstantExpressionVisitor visitor(/*loopIndices=*/nullptr);
1341 return !visitor.visitExpression(expr);
1342}
1343
John Stiles958f4b52021-03-17 16:39:49 -04001344bool Analysis::CanExitWithoutReturningValue(const FunctionDeclaration& funcDecl,
1345 const Statement& body) {
1346 if (funcDecl.returnType().isVoid()) {
1347 return false;
1348 }
John Stilesb3dcbb12021-03-04 16:00:20 -05001349 ReturnsOnAllPathsVisitor visitor;
John Stiles958f4b52021-03-17 16:39:49 -04001350 visitor.visitStatement(body);
John Stilesb3dcbb12021-03-04 16:00:20 -05001351 return !visitor.fFoundReturn;
1352}
1353
John Stiles2ecc5952021-09-01 14:41:36 -04001354void Analysis::VerifyStaticTestsAndExpressions(const Program& program) {
1355 class TestsAndExpressions : public ProgramVisitor {
John Stiles0fc6bed2021-09-01 11:35:59 -04001356 public:
John Stiles2ecc5952021-09-01 14:41:36 -04001357 TestsAndExpressions(const Context& ctx) : fContext(ctx) {}
John Stiles0fc6bed2021-09-01 11:35:59 -04001358
1359 using ProgramVisitor::visitProgramElement;
1360
1361 bool visitStatement(const Statement& stmt) override {
John Stiles2ecc5952021-09-01 14:41:36 -04001362 if (!fContext.fConfig->fSettings.fPermitInvalidStaticTests) {
1363 switch (stmt.kind()) {
1364 case Statement::Kind::kIf:
1365 if (stmt.as<IfStatement>().isStatic()) {
1366 fContext.fErrors->error(stmt.fOffset, "static if has non-static test");
1367 }
1368 break;
John Stiles0fc6bed2021-09-01 11:35:59 -04001369
John Stiles2ecc5952021-09-01 14:41:36 -04001370 case Statement::Kind::kSwitch:
1371 if (stmt.as<SwitchStatement>().isStatic()) {
1372 fContext.fErrors->error(stmt.fOffset,
1373 "static switch has non-static test");
1374 }
1375 break;
John Stiles0fc6bed2021-09-01 11:35:59 -04001376
John Stiles2ecc5952021-09-01 14:41:36 -04001377 default:
1378 break;
1379 }
John Stiles0fc6bed2021-09-01 11:35:59 -04001380 }
1381 return INHERITED::visitStatement(stmt);
1382 }
1383
John Stiles2ecc5952021-09-01 14:41:36 -04001384 bool visitExpression(const Expression& expr) override {
1385 switch (expr.kind()) {
1386 case Expression::Kind::kFunctionCall: {
1387 const FunctionDeclaration& decl = expr.as<FunctionCall>().function();
1388 if (!decl.isBuiltin() && !decl.definition()) {
1389 fContext.fErrors->error(expr.fOffset, "function '" + decl.description() +
1390 "' is not defined");
1391 }
1392 break;
1393 }
1394 case Expression::Kind::kExternalFunctionReference:
1395 case Expression::Kind::kFunctionReference:
Brian Osman3099f792021-09-01 13:12:16 -04001396 case Expression::Kind::kMethodReference:
John Stiles2ecc5952021-09-01 14:41:36 -04001397 case Expression::Kind::kTypeReference:
1398 SkDEBUGFAIL("invalid reference-expr, should have been reported by coerce()");
1399 fContext.fErrors->error(expr.fOffset, "invalid expression");
1400 break;
1401 default:
1402 if (expr.type() == *fContext.fTypes.fInvalid) {
1403 fContext.fErrors->error(expr.fOffset, "invalid expression");
1404 }
1405 break;
1406 }
1407 return INHERITED::visitExpression(expr);
John Stiles0fc6bed2021-09-01 11:35:59 -04001408 }
1409
1410 private:
1411 using INHERITED = ProgramVisitor;
John Stiles2ecc5952021-09-01 14:41:36 -04001412 const Context& fContext;
John Stiles0fc6bed2021-09-01 11:35:59 -04001413 };
1414
John Stiles0fc6bed2021-09-01 11:35:59 -04001415 // Check all of the program's owned elements. (Built-in elements are assumed to be valid.)
John Stiles2ecc5952021-09-01 14:41:36 -04001416 TestsAndExpressions visitor{*program.fContext};
John Stiles0fc6bed2021-09-01 11:35:59 -04001417 for (const std::unique_ptr<ProgramElement>& element : program.ownedElements()) {
John Stiles2ecc5952021-09-01 14:41:36 -04001418 visitor.visitProgramElement(*element);
John Stiles0fc6bed2021-09-01 11:35:59 -04001419 }
1420}
1421
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001422////////////////////////////////////////////////////////////////////////////////
1423// ProgramVisitor
1424
Brian Osman133724c2020-10-28 14:14:39 -04001425bool ProgramVisitor::visit(const Program& program) {
1426 for (const ProgramElement* pe : program.elements()) {
Brian Osman1179fcf2020-10-08 16:04:40 -04001427 if (this->visitProgramElement(*pe)) {
John Stiles933abe32020-08-28 11:58:40 -04001428 return true;
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001429 }
1430 }
John Stiles933abe32020-08-28 11:58:40 -04001431 return false;
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001432}
1433
John Stiles48b25582021-03-11 14:26:42 -05001434template <typename T> bool TProgramVisitor<T>::visitExpression(typename T::Expression& e) {
John Stiles70b82422020-09-30 10:55:12 -04001435 switch (e.kind()) {
Ethan Nicholase6592142020-09-08 10:22:09 -04001436 case Expression::Kind::kBoolLiteral:
Brian Osmanbe0b3b72021-01-06 14:27:35 -05001437 case Expression::Kind::kExternalFunctionReference:
Ethan Nicholase6592142020-09-08 10:22:09 -04001438 case Expression::Kind::kFloatLiteral:
1439 case Expression::Kind::kFunctionReference:
1440 case Expression::Kind::kIntLiteral:
Brian Osman3099f792021-09-01 13:12:16 -04001441 case Expression::Kind::kMethodReference:
Ethan Nicholas549c6b82021-06-25 12:31:44 -04001442 case Expression::Kind::kPoison:
Ethan Nicholase6592142020-09-08 10:22:09 -04001443 case Expression::Kind::kSetting:
1444 case Expression::Kind::kTypeReference:
1445 case Expression::Kind::kVariableReference:
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001446 // Leaf expressions return false
1447 return false;
John Stiles70b82422020-09-30 10:55:12 -04001448
Ethan Nicholase6592142020-09-08 10:22:09 -04001449 case Expression::Kind::kBinary: {
John Stiles70b82422020-09-30 10:55:12 -04001450 auto& b = e.template as<BinaryExpression>();
John Stiles48b25582021-03-11 14:26:42 -05001451 return (b.left() && this->visitExpressionPtr(b.left())) ||
1452 (b.right() && this->visitExpressionPtr(b.right()));
John Stiles70b82422020-09-30 10:55:12 -04001453 }
Brian Osmaneb0f29d2021-08-04 11:34:16 -04001454 case Expression::Kind::kChildCall: {
1455 // We don't visit the child variable itself, just the arguments
1456 auto& c = e.template as<ChildCall>();
1457 for (auto& arg : c.arguments()) {
1458 if (arg && this->visitExpressionPtr(arg)) { return true; }
1459 }
1460 return false;
1461 }
John Stiles7384b372021-04-01 13:48:15 -04001462 case Expression::Kind::kConstructorArray:
John Stilese3ae9682021-08-05 10:35:01 -04001463 case Expression::Kind::kConstructorArrayCast:
John Stiles8cad6372021-04-07 12:31:13 -04001464 case Expression::Kind::kConstructorCompound:
1465 case Expression::Kind::kConstructorCompoundCast:
John Stiles2938eea2021-04-01 18:58:25 -04001466 case Expression::Kind::kConstructorDiagonalMatrix:
John Stiles5abb9e12021-04-06 13:47:19 -04001467 case Expression::Kind::kConstructorMatrixResize:
John Stilesfd7252f2021-04-04 22:24:40 -04001468 case Expression::Kind::kConstructorScalarCast:
John Stilesd47330f2021-04-08 23:25:52 -04001469 case Expression::Kind::kConstructorSplat:
1470 case Expression::Kind::kConstructorStruct: {
John Stiles7384b372021-04-01 13:48:15 -04001471 auto& c = e.asAnyConstructor();
1472 for (auto& arg : c.argumentSpan()) {
John Stiles48b25582021-03-11 14:26:42 -05001473 if (this->visitExpressionPtr(arg)) { return true; }
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001474 }
John Stiles70b82422020-09-30 10:55:12 -04001475 return false;
1476 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001477 case Expression::Kind::kExternalFunctionCall: {
John Stiles70b82422020-09-30 10:55:12 -04001478 auto& c = e.template as<ExternalFunctionCall>();
Ethan Nicholas6e86ec92020-09-30 14:29:56 -04001479 for (auto& arg : c.arguments()) {
John Stiles48b25582021-03-11 14:26:42 -05001480 if (this->visitExpressionPtr(arg)) { return true; }
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001481 }
John Stiles70b82422020-09-30 10:55:12 -04001482 return false;
1483 }
John Stilesd7ab4502020-09-24 22:41:00 -04001484 case Expression::Kind::kFieldAccess:
John Stiles48b25582021-03-11 14:26:42 -05001485 return this->visitExpressionPtr(e.template as<FieldAccess>().base());
John Stiles70b82422020-09-30 10:55:12 -04001486
Ethan Nicholase6592142020-09-08 10:22:09 -04001487 case Expression::Kind::kFunctionCall: {
John Stiles70b82422020-09-30 10:55:12 -04001488 auto& c = e.template as<FunctionCall>();
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001489 for (auto& arg : c.arguments()) {
John Stiles48b25582021-03-11 14:26:42 -05001490 if (arg && this->visitExpressionPtr(arg)) { return true; }
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001491 }
John Stiles70b82422020-09-30 10:55:12 -04001492 return false;
1493 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001494 case Expression::Kind::kIndex: {
John Stiles70b82422020-09-30 10:55:12 -04001495 auto& i = e.template as<IndexExpression>();
John Stiles48b25582021-03-11 14:26:42 -05001496 return this->visitExpressionPtr(i.base()) || this->visitExpressionPtr(i.index());
John Stiles70b82422020-09-30 10:55:12 -04001497 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001498 case Expression::Kind::kPostfix:
John Stiles48b25582021-03-11 14:26:42 -05001499 return this->visitExpressionPtr(e.template as<PostfixExpression>().operand());
John Stiles70b82422020-09-30 10:55:12 -04001500
Ethan Nicholase6592142020-09-08 10:22:09 -04001501 case Expression::Kind::kPrefix:
John Stiles48b25582021-03-11 14:26:42 -05001502 return this->visitExpressionPtr(e.template as<PrefixExpression>().operand());
John Stiles70b82422020-09-30 10:55:12 -04001503
Brian Osman010ce6a2020-10-19 16:34:10 -04001504 case Expression::Kind::kSwizzle: {
1505 auto& s = e.template as<Swizzle>();
John Stiles48b25582021-03-11 14:26:42 -05001506 return s.base() && this->visitExpressionPtr(s.base());
Brian Osman010ce6a2020-10-19 16:34:10 -04001507 }
John Stiles70b82422020-09-30 10:55:12 -04001508
Ethan Nicholase6592142020-09-08 10:22:09 -04001509 case Expression::Kind::kTernary: {
John Stiles70b82422020-09-30 10:55:12 -04001510 auto& t = e.template as<TernaryExpression>();
John Stiles48b25582021-03-11 14:26:42 -05001511 return this->visitExpressionPtr(t.test()) ||
1512 (t.ifTrue() && this->visitExpressionPtr(t.ifTrue())) ||
1513 (t.ifFalse() && this->visitExpressionPtr(t.ifFalse()));
John Stiles70b82422020-09-30 10:55:12 -04001514 }
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001515 default:
1516 SkUNREACHABLE;
1517 }
1518}
1519
John Stiles48b25582021-03-11 14:26:42 -05001520template <typename T> bool TProgramVisitor<T>::visitStatement(typename T::Statement& s) {
John Stiles70b82422020-09-30 10:55:12 -04001521 switch (s.kind()) {
Ethan Nicholase6592142020-09-08 10:22:09 -04001522 case Statement::Kind::kBreak:
1523 case Statement::Kind::kContinue:
1524 case Statement::Kind::kDiscard:
John Stiles98c1f822020-09-09 14:18:53 -04001525 case Statement::Kind::kInlineMarker:
Ethan Nicholase6592142020-09-08 10:22:09 -04001526 case Statement::Kind::kNop:
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001527 // Leaf statements just return false
1528 return false;
John Stiles70b82422020-09-30 10:55:12 -04001529
Ethan Nicholase6592142020-09-08 10:22:09 -04001530 case Statement::Kind::kBlock:
John Stiles70b82422020-09-30 10:55:12 -04001531 for (auto& stmt : s.template as<Block>().children()) {
John Stiles48b25582021-03-11 14:26:42 -05001532 if (stmt && this->visitStatementPtr(stmt)) {
Ethan Nicholas7bd60432020-09-25 14:31:59 -04001533 return true;
1534 }
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001535 }
1536 return false;
John Stiles70b82422020-09-30 10:55:12 -04001537
John Stilesa0e56e32021-03-03 13:14:37 -05001538 case Statement::Kind::kSwitchCase: {
1539 auto& sc = s.template as<SwitchCase>();
John Stiles48b25582021-03-11 14:26:42 -05001540 if (sc.value() && this->visitExpressionPtr(sc.value())) {
John Stilesa0e56e32021-03-03 13:14:37 -05001541 return true;
1542 }
John Stiles48b25582021-03-11 14:26:42 -05001543 return this->visitStatementPtr(sc.statement());
John Stilesa0e56e32021-03-03 13:14:37 -05001544 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001545 case Statement::Kind::kDo: {
John Stiles70b82422020-09-30 10:55:12 -04001546 auto& d = s.template as<DoStatement>();
John Stiles48b25582021-03-11 14:26:42 -05001547 return this->visitExpressionPtr(d.test()) || this->visitStatementPtr(d.statement());
John Stiles70b82422020-09-30 10:55:12 -04001548 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001549 case Statement::Kind::kExpression:
John Stiles48b25582021-03-11 14:26:42 -05001550 return this->visitExpressionPtr(s.template as<ExpressionStatement>().expression());
John Stiles70b82422020-09-30 10:55:12 -04001551
Ethan Nicholase6592142020-09-08 10:22:09 -04001552 case Statement::Kind::kFor: {
John Stiles70b82422020-09-30 10:55:12 -04001553 auto& f = s.template as<ForStatement>();
John Stiles48b25582021-03-11 14:26:42 -05001554 return (f.initializer() && this->visitStatementPtr(f.initializer())) ||
1555 (f.test() && this->visitExpressionPtr(f.test())) ||
1556 (f.next() && this->visitExpressionPtr(f.next())) ||
1557 this->visitStatementPtr(f.statement());
John Stiles70b82422020-09-30 10:55:12 -04001558 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001559 case Statement::Kind::kIf: {
John Stiles70b82422020-09-30 10:55:12 -04001560 auto& i = s.template as<IfStatement>();
John Stiles48b25582021-03-11 14:26:42 -05001561 return (i.test() && this->visitExpressionPtr(i.test())) ||
1562 (i.ifTrue() && this->visitStatementPtr(i.ifTrue())) ||
1563 (i.ifFalse() && this->visitStatementPtr(i.ifFalse()));
John Stiles70b82422020-09-30 10:55:12 -04001564 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001565 case Statement::Kind::kReturn: {
John Stiles70b82422020-09-30 10:55:12 -04001566 auto& r = s.template as<ReturnStatement>();
John Stiles48b25582021-03-11 14:26:42 -05001567 return r.expression() && this->visitExpressionPtr(r.expression());
John Stiles70b82422020-09-30 10:55:12 -04001568 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001569 case Statement::Kind::kSwitch: {
John Stiles70b82422020-09-30 10:55:12 -04001570 auto& sw = s.template as<SwitchStatement>();
John Stiles48b25582021-03-11 14:26:42 -05001571 if (this->visitExpressionPtr(sw.value())) {
John Stiles70b82422020-09-30 10:55:12 -04001572 return true;
1573 }
John Stiles48b25582021-03-11 14:26:42 -05001574 for (auto& c : sw.cases()) {
1575 if (this->visitStatementPtr(c)) {
John Stiles70b82422020-09-30 10:55:12 -04001576 return true;
1577 }
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001578 }
John Stiles70b82422020-09-30 10:55:12 -04001579 return false;
1580 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001581 case Statement::Kind::kVarDeclaration: {
John Stiles70b82422020-09-30 10:55:12 -04001582 auto& v = s.template as<VarDeclaration>();
John Stiles48b25582021-03-11 14:26:42 -05001583 return v.value() && this->visitExpressionPtr(v.value());
John Stiles70b82422020-09-30 10:55:12 -04001584 }
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001585 default:
1586 SkUNREACHABLE;
1587 }
1588}
1589
John Stiles48b25582021-03-11 14:26:42 -05001590template <typename T> bool TProgramVisitor<T>::visitProgramElement(typename T::ProgramElement& pe) {
John Stiles70b82422020-09-30 10:55:12 -04001591 switch (pe.kind()) {
Ethan Nicholase6592142020-09-08 10:22:09 -04001592 case ProgramElement::Kind::kExtension:
John Stiles569249b2020-11-03 12:18:22 -05001593 case ProgramElement::Kind::kFunctionPrototype:
John Stilesd39aec02020-12-03 10:42:26 -05001594 case ProgramElement::Kind::kInterfaceBlock:
Ethan Nicholase6592142020-09-08 10:22:09 -04001595 case ProgramElement::Kind::kModifiers:
John Stilesdc75a972020-11-25 16:24:55 -05001596 case ProgramElement::Kind::kStructDefinition:
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001597 // Leaf program elements just return false by default
1598 return false;
John Stiles70b82422020-09-30 10:55:12 -04001599
Ethan Nicholase6592142020-09-08 10:22:09 -04001600 case ProgramElement::Kind::kFunction:
John Stiles48b25582021-03-11 14:26:42 -05001601 return this->visitStatementPtr(pe.template as<FunctionDefinition>().body());
John Stiles70b82422020-09-30 10:55:12 -04001602
Brian Osmanc0213602020-10-06 14:43:32 -04001603 case ProgramElement::Kind::kGlobalVar:
John Stiles48b25582021-03-11 14:26:42 -05001604 return this->visitStatementPtr(pe.template as<GlobalVarDeclaration>().declaration());
John Stiles70b82422020-09-30 10:55:12 -04001605
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001606 default:
1607 SkUNREACHABLE;
1608 }
1609}
1610
John Stiles48b25582021-03-11 14:26:42 -05001611template class TProgramVisitor<ProgramVisitorTypes>;
1612template class TProgramVisitor<ProgramWriterTypes>;
John Stiles70b82422020-09-30 10:55:12 -04001613
John Stilesa6841be2020-08-06 14:11:56 -04001614} // namespace SkSL