blob: 24d6cfc15f033936429b467df1ee93be3902a7cd [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"
Brian Osman00185012021-02-04 16:07:11 -050014#include "src/sksl/SkSLCompiler.h"
John Stilesdce4d3e2020-09-25 14:35:13 -040015#include "src/sksl/SkSLErrorReporter.h"
Michael Ludwig8f3a8362020-06-29 17:27:00 -040016#include "src/sksl/ir/SkSLExpression.h"
17#include "src/sksl/ir/SkSLProgram.h"
Michael Ludwig8f3a8362020-06-29 17:27:00 -040018
19// ProgramElements
20#include "src/sksl/ir/SkSLEnum.h"
21#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/SkSLSection.h"
25#include "src/sksl/ir/SkSLVarDeclarations.h"
26
27// Statements
28#include "src/sksl/ir/SkSLBlock.h"
29#include "src/sksl/ir/SkSLBreakStatement.h"
30#include "src/sksl/ir/SkSLContinueStatement.h"
31#include "src/sksl/ir/SkSLDiscardStatement.h"
32#include "src/sksl/ir/SkSLDoStatement.h"
33#include "src/sksl/ir/SkSLExpressionStatement.h"
34#include "src/sksl/ir/SkSLForStatement.h"
35#include "src/sksl/ir/SkSLIfStatement.h"
36#include "src/sksl/ir/SkSLNop.h"
37#include "src/sksl/ir/SkSLReturnStatement.h"
38#include "src/sksl/ir/SkSLSwitchStatement.h"
Michael Ludwig8f3a8362020-06-29 17:27:00 -040039
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"
Brian Osmanbe0b3b72021-01-06 14:27:35 -050045#include "src/sksl/ir/SkSLExternalFunctionReference.h"
Michael Ludwig8f3a8362020-06-29 17:27:00 -040046#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"
Michael Ludwig8f3a8362020-06-29 17:27:00 -040053#include "src/sksl/ir/SkSLPostfixExpression.h"
54#include "src/sksl/ir/SkSLPrefixExpression.h"
55#include "src/sksl/ir/SkSLSetting.h"
56#include "src/sksl/ir/SkSLSwizzle.h"
57#include "src/sksl/ir/SkSLTernaryExpression.h"
58#include "src/sksl/ir/SkSLTypeReference.h"
59#include "src/sksl/ir/SkSLVariableReference.h"
60
61namespace SkSL {
62
63namespace {
64
65static bool is_sample_call_to_fp(const FunctionCall& fc, const Variable& fp) {
Ethan Nicholas0dec9922020-10-05 15:51:52 -040066 const FunctionDeclaration& f = fc.function();
Ethan Nicholased84b732020-10-08 11:45:44 -040067 return f.isBuiltin() && f.name() == "sample" && fc.arguments().size() >= 1 &&
Ethan Nicholas0dec9922020-10-05 15:51:52 -040068 fc.arguments()[0]->is<VariableReference>() &&
Ethan Nicholas78686922020-10-08 06:46:27 -040069 fc.arguments()[0]->as<VariableReference>().variable() == &fp;
Michael Ludwig8f3a8362020-06-29 17:27:00 -040070}
71
Brian Osman1298bc42020-06-30 13:39:35 -040072// Visitor that determines the merged SampleUsage for a given child 'fp' in the program.
73class MergeSampleUsageVisitor : public ProgramVisitor {
Michael Ludwig8f3a8362020-06-29 17:27:00 -040074public:
John Stiles933abe32020-08-28 11:58:40 -040075 MergeSampleUsageVisitor(const Context& context, const Variable& fp)
76 : fContext(context), fFP(fp) {}
Michael Ludwig8f3a8362020-06-29 17:27:00 -040077
Brian Osman1298bc42020-06-30 13:39:35 -040078 SampleUsage visit(const Program& program) {
79 fUsage = SampleUsage(); // reset to none
John Stilesd7ab4502020-09-24 22:41:00 -040080 INHERITED::visit(program);
Brian Osman1298bc42020-06-30 13:39:35 -040081 return fUsage;
Michael Ludwig8f3a8362020-06-29 17:27:00 -040082 }
83
84protected:
John Stiles933abe32020-08-28 11:58:40 -040085 const Context& fContext;
Michael Ludwig8f3a8362020-06-29 17:27:00 -040086 const Variable& fFP;
Brian Osman1298bc42020-06-30 13:39:35 -040087 SampleUsage fUsage;
Michael Ludwig8f3a8362020-06-29 17:27:00 -040088
89 bool visitExpression(const Expression& e) override {
Brian Osman1298bc42020-06-30 13:39:35 -040090 // Looking for sample(fp, inColor?, ...)
Ethan Nicholase6592142020-09-08 10:22:09 -040091 if (e.kind() == Expression::Kind::kFunctionCall) {
John Stiles403a3632020-08-20 12:11:48 -040092 const FunctionCall& fc = e.as<FunctionCall>();
Brian Osman1298bc42020-06-30 13:39:35 -040093 if (is_sample_call_to_fp(fc, fFP)) {
94 // Determine the type of call at this site, and merge it with the accumulated state
Ethan Nicholas0dec9922020-10-05 15:51:52 -040095 const Expression* lastArg = fc.arguments().back().get();
Brian Osman1298bc42020-06-30 13:39:35 -040096
John Stiles54e7c052021-01-11 14:22:36 -050097 if (lastArg->type() == *fContext.fTypes.fFloat2) {
Brian Osman1298bc42020-06-30 13:39:35 -040098 fUsage.merge(SampleUsage::Explicit());
John Stiles54e7c052021-01-11 14:22:36 -050099 } else if (lastArg->type() == *fContext.fTypes.fFloat3x3) {
Brian Osman1298bc42020-06-30 13:39:35 -0400100 // Determine the type of matrix for this call site
101 if (lastArg->isConstantOrUniform()) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400102 if (lastArg->kind() == Expression::Kind::kVariableReference ||
103 lastArg->kind() == Expression::Kind::kConstructor) {
Brian Osman1298bc42020-06-30 13:39:35 -0400104 // FIXME if this is a constant, we should parse the float3x3 constructor
105 // and determine if the resulting matrix introduces perspective.
106 fUsage.merge(SampleUsage::UniformMatrix(lastArg->description()));
107 } else {
108 // FIXME this is really to workaround a restriction of the downstream
109 // code that relies on the SampleUsage's fExpression to identify uniform
110 // names. Once they are tracked separately, any uniform expression can
111 // work, but right now this avoids issues from '0.5 * matrix' that is
112 // both a constant AND a uniform.
113 fUsage.merge(SampleUsage::VariableMatrix());
114 }
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400115 } else {
Brian Osman1298bc42020-06-30 13:39:35 -0400116 fUsage.merge(SampleUsage::VariableMatrix());
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400117 }
118 } else {
Brian Osman1298bc42020-06-30 13:39:35 -0400119 // The only other signatures do pass-through sampling
120 fUsage.merge(SampleUsage::PassThrough());
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400121 }
Brian Osman1298bc42020-06-30 13:39:35 -0400122 // NOTE: we don't return true here just because we found a sample call. We need to
123 // process the entire program and merge across all encountered calls.
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400124 }
125 }
126
John Stilesd7ab4502020-09-24 22:41:00 -0400127 return INHERITED::visitExpression(e);
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400128 }
129
John Stiles7571f9e2020-09-02 22:42:33 -0400130 using INHERITED = ProgramVisitor;
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400131};
132
Brian Osman92aac1e2020-08-05 16:48:58 -0400133// Visitor that searches through the program for references to a particular builtin variable
134class BuiltinVariableVisitor : public ProgramVisitor {
135public:
136 BuiltinVariableVisitor(int builtin) : fBuiltin(builtin) {}
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400137
138 bool visitExpression(const Expression& e) override {
Brian Osman79457ef2020-09-24 15:01:27 -0400139 if (e.is<VariableReference>()) {
John Stiles403a3632020-08-20 12:11:48 -0400140 const VariableReference& var = e.as<VariableReference>();
Ethan Nicholas78686922020-10-08 06:46:27 -0400141 return var.variable()->modifiers().fLayout.fBuiltin == fBuiltin;
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400142 }
John Stilesd7ab4502020-09-24 22:41:00 -0400143 return INHERITED::visitExpression(e);
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400144 }
145
Brian Osman92aac1e2020-08-05 16:48:58 -0400146 int fBuiltin;
147
John Stiles7571f9e2020-09-02 22:42:33 -0400148 using INHERITED = ProgramVisitor;
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400149};
150
Ethan Nicholas6e0fa402020-08-20 14:08:23 -0400151// Visitor that counts the number of nodes visited
152class NodeCountVisitor : public ProgramVisitor {
153public:
John Stiles2c1e4922020-10-01 09:14:14 -0400154 NodeCountVisitor(int limit) : fLimit(limit) {}
155
Ethan Nicholas6e0fa402020-08-20 14:08:23 -0400156 int visit(const Statement& s) {
Ethan Nicholas6e0fa402020-08-20 14:08:23 -0400157 this->visitStatement(s);
158 return fCount;
159 }
160
161 bool visitExpression(const Expression& e) override {
162 ++fCount;
John Stiles9b9415e2020-11-23 14:48:06 -0500163 return (fCount >= fLimit) || INHERITED::visitExpression(e);
Ethan Nicholas6e0fa402020-08-20 14:08:23 -0400164 }
165
166 bool visitProgramElement(const ProgramElement& p) override {
167 ++fCount;
John Stiles9b9415e2020-11-23 14:48:06 -0500168 return (fCount >= fLimit) || INHERITED::visitProgramElement(p);
Ethan Nicholas6e0fa402020-08-20 14:08:23 -0400169 }
170
171 bool visitStatement(const Statement& s) override {
172 ++fCount;
John Stiles9b9415e2020-11-23 14:48:06 -0500173 return (fCount >= fLimit) || INHERITED::visitStatement(s);
Ethan Nicholas6e0fa402020-08-20 14:08:23 -0400174 }
175
176private:
John Stiles2c1e4922020-10-01 09:14:14 -0400177 int fCount = 0;
178 int fLimit;
Ethan Nicholas6e0fa402020-08-20 14:08:23 -0400179
John Stiles7571f9e2020-09-02 22:42:33 -0400180 using INHERITED = ProgramVisitor;
Ethan Nicholas6e0fa402020-08-20 14:08:23 -0400181};
182
Brian Osman010ce6a2020-10-19 16:34:10 -0400183class ProgramUsageVisitor : public ProgramVisitor {
Brian Osman2e25ff42020-10-15 10:32:04 -0400184public:
Brian Osman010ce6a2020-10-19 16:34:10 -0400185 ProgramUsageVisitor(ProgramUsage* usage, int delta) : fUsage(usage), fDelta(delta) {}
186
Brian Osman2e25ff42020-10-15 10:32:04 -0400187 bool visitExpression(const Expression& e) override {
188 if (e.is<FunctionCall>()) {
189 const FunctionDeclaration* f = &e.as<FunctionCall>().function();
Brian Osman010ce6a2020-10-19 16:34:10 -0400190 fUsage->fCallCounts[f] += fDelta;
191 SkASSERT(fUsage->fCallCounts[f] >= 0);
192 } else if (e.is<VariableReference>()) {
193 const VariableReference& ref = e.as<VariableReference>();
194 ProgramUsage::VariableCounts& counts = fUsage->fVariableCounts[ref.variable()];
195 switch (ref.refKind()) {
196 case VariableRefKind::kRead:
197 counts.fRead += fDelta;
198 break;
199 case VariableRefKind::kWrite:
200 counts.fWrite += fDelta;
201 break;
202 case VariableRefKind::kReadWrite:
203 case VariableRefKind::kPointer:
204 counts.fRead += fDelta;
205 counts.fWrite += fDelta;
206 break;
207 }
208 SkASSERT(counts.fRead >= 0 && counts.fWrite >= 0);
Brian Osman2e25ff42020-10-15 10:32:04 -0400209 }
210 return INHERITED::visitExpression(e);
211 }
212
Brian Osman010ce6a2020-10-19 16:34:10 -0400213 using ProgramVisitor::visitProgramElement;
214 using ProgramVisitor::visitStatement;
215
216 ProgramUsage* fUsage;
217 int fDelta;
Brian Osman2e25ff42020-10-15 10:32:04 -0400218 using INHERITED = ProgramVisitor;
219};
220
Ethan Nicholas765d2fe2020-08-26 08:29:55 -0400221class VariableWriteVisitor : public ProgramVisitor {
222public:
223 VariableWriteVisitor(const Variable* var)
224 : fVar(var) {}
225
226 bool visit(const Statement& s) {
227 return this->visitStatement(s);
228 }
229
230 bool visitExpression(const Expression& e) override {
Brian Osman79457ef2020-09-24 15:01:27 -0400231 if (e.is<VariableReference>()) {
Ethan Nicholas765d2fe2020-08-26 08:29:55 -0400232 const VariableReference& ref = e.as<VariableReference>();
Ethan Nicholas453f67f2020-10-09 10:43:45 -0400233 if (ref.variable() == fVar &&
234 (ref.refKind() == VariableReference::RefKind::kWrite ||
235 ref.refKind() == VariableReference::RefKind::kReadWrite ||
236 ref.refKind() == VariableReference::RefKind::kPointer)) {
Ethan Nicholas765d2fe2020-08-26 08:29:55 -0400237 return true;
238 }
239 }
John Stilesd7ab4502020-09-24 22:41:00 -0400240 return INHERITED::visitExpression(e);
Ethan Nicholas765d2fe2020-08-26 08:29:55 -0400241 }
242
243private:
244 const Variable* fVar;
245
John Stiles7571f9e2020-09-02 22:42:33 -0400246 using INHERITED = ProgramVisitor;
Ethan Nicholas765d2fe2020-08-26 08:29:55 -0400247};
248
John Stilesa976da72020-09-25 23:06:26 -0400249// If a caller doesn't care about errors, we can use this trivial reporter that just counts up.
250class TrivialErrorReporter : public ErrorReporter {
251public:
252 void error(int offset, String) override { ++fErrorCount; }
253 int errorCount() override { return fErrorCount; }
John Stiles8d3642e2021-01-22 09:50:04 -0500254 void setErrorCount(int c) override { fErrorCount = c; }
John Stilesa976da72020-09-25 23:06:26 -0400255
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 Stilesb21fac22020-12-04 15:36:49 -0500265 IsAssignableVisitor(ErrorReporter* errors) : fErrors(errors) {}
John Stilesdce4d3e2020-09-25 14:35:13 -0400266
John Stilesb21fac22020-12-04 15:36:49 -0500267 bool visit(Expression& expr, Analysis::AssignmentInfo* info) {
Ethan Nicholas67a0a8a2021-01-13 12:36:02 -0500268 int oldErrorCount = fErrors->errorCount();
John Stilesdce4d3e2020-09-25 14:35:13 -0400269 this->visitExpression(expr);
John Stilesb21fac22020-12-04 15:36:49 -0500270 if (info) {
271 info->fAssignedVar = fAssignedVar;
John Stilesb21fac22020-12-04 15:36:49 -0500272 }
Ethan Nicholas67a0a8a2021-01-13 12:36:02 -0500273 return fErrors->errorCount() == oldErrorCount;
John Stilesdce4d3e2020-09-25 14:35:13 -0400274 }
275
276 void visitExpression(Expression& expr) {
277 switch (expr.kind()) {
278 case Expression::Kind::kVariableReference: {
279 VariableReference& varRef = expr.as<VariableReference>();
Ethan Nicholas78686922020-10-08 06:46:27 -0400280 const Variable* var = varRef.variable();
Ethan Nicholas041fd0a2020-10-07 16:42:04 -0400281 if (var->modifiers().fFlags & (Modifiers::kConst_Flag | Modifiers::kUniform_Flag |
282 Modifiers::kVarying_Flag)) {
John Stilesa976da72020-09-25 23:06:26 -0400283 fErrors->error(expr.fOffset,
Ethan Nicholase2c49992020-10-05 11:49:11 -0400284 "cannot modify immutable variable '" + var->name() + "'");
John Stilesb21fac22020-12-04 15:36:49 -0500285 } else {
286 SkASSERT(fAssignedVar == nullptr);
287 fAssignedVar = &varRef;
John Stilesdce4d3e2020-09-25 14:35:13 -0400288 }
289 break;
290 }
291 case Expression::Kind::kFieldAccess:
Ethan Nicholas7a95b202020-10-09 11:55:40 -0400292 this->visitExpression(*expr.as<FieldAccess>().base());
John Stilesdce4d3e2020-09-25 14:35:13 -0400293 break;
294
295 case Expression::Kind::kSwizzle: {
296 const Swizzle& swizzle = expr.as<Swizzle>();
297 this->checkSwizzleWrite(swizzle);
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400298 this->visitExpression(*swizzle.base());
John Stilesdce4d3e2020-09-25 14:35:13 -0400299 break;
300 }
John Stiles47c0a742021-02-09 09:30:35 -0500301 case Expression::Kind::kIndex:
302 this->visitExpression(*expr.as<IndexExpression>().base());
John Stilesdce4d3e2020-09-25 14:35:13 -0400303 break;
John Stiles47c0a742021-02-09 09:30:35 -0500304
John Stilesdce4d3e2020-09-25 14:35:13 -0400305 default:
John Stilesa976da72020-09-25 23:06:26 -0400306 fErrors->error(expr.fOffset, "cannot assign to this expression");
John Stilesdce4d3e2020-09-25 14:35:13 -0400307 break;
308 }
309 }
310
311private:
312 void checkSwizzleWrite(const Swizzle& swizzle) {
313 int bits = 0;
John Stiles6e88e042021-02-19 14:09:38 -0500314 for (int8_t idx : swizzle.components()) {
315 SkASSERT(idx >= SwizzleComponent::X && idx <= SwizzleComponent::W);
John Stilesdce4d3e2020-09-25 14:35:13 -0400316 int bit = 1 << idx;
317 if (bits & bit) {
John Stilesa976da72020-09-25 23:06:26 -0400318 fErrors->error(swizzle.fOffset,
319 "cannot write to the same swizzle field more than once");
John Stilesdce4d3e2020-09-25 14:35:13 -0400320 break;
321 }
322 bits |= bit;
323 }
324 }
325
John Stilesa976da72020-09-25 23:06:26 -0400326 ErrorReporter* fErrors;
John Stilesb21fac22020-12-04 15:36:49 -0500327 VariableReference* fAssignedVar = nullptr;
John Stilesdce4d3e2020-09-25 14:35:13 -0400328
329 using INHERITED = ProgramVisitor;
330};
331
John Stiles642cde22021-02-23 14:57:01 -0500332class SwitchCaseContainsExit : public ProgramVisitor {
333public:
334 SwitchCaseContainsExit(bool conditionalExits) : fConditionalExits(conditionalExits) {}
335
336 bool visitStatement(const Statement& stmt) override {
337 switch (stmt.kind()) {
338 case Statement::Kind::kBlock:
John Stilesa0e56e32021-03-03 13:14:37 -0500339 case Statement::Kind::kSwitchCase:
John Stiles642cde22021-02-23 14:57:01 -0500340 return INHERITED::visitStatement(stmt);
341
342 case Statement::Kind::kReturn:
343 // Returns are an early exit regardless of the surrounding control structures.
344 return fConditionalExits ? fInConditional : !fInConditional;
345
346 case Statement::Kind::kContinue:
347 // Continues are an early exit from switches, but not loops.
348 return !fInLoop &&
349 (fConditionalExits ? fInConditional : !fInConditional);
350
351 case Statement::Kind::kBreak:
352 // Breaks cannot escape from switches or loops.
353 return !fInLoop && !fInSwitch &&
354 (fConditionalExits ? fInConditional : !fInConditional);
355
356 case Statement::Kind::kIf: {
357 ++fInConditional;
358 bool result = INHERITED::visitStatement(stmt);
359 --fInConditional;
360 return result;
361 }
362
363 case Statement::Kind::kFor:
364 case Statement::Kind::kDo: {
365 // Loops are treated as conditionals because a loop could potentially execute zero
366 // times. We don't have a straightforward way to determine that a loop definitely
367 // executes at least once.
368 ++fInConditional;
369 ++fInLoop;
370 bool result = INHERITED::visitStatement(stmt);
371 --fInLoop;
372 --fInConditional;
373 return result;
374 }
375
376 case Statement::Kind::kSwitch: {
377 ++fInSwitch;
378 bool result = INHERITED::visitStatement(stmt);
379 --fInSwitch;
380 return result;
381 }
382
383 default:
384 return false;
385 }
386 }
387
388 bool fConditionalExits = false;
389 int fInConditional = 0;
390 int fInLoop = 0;
391 int fInSwitch = 0;
392 using INHERITED = ProgramVisitor;
393};
394
John Stilesb3dcbb12021-03-04 16:00:20 -0500395class ReturnsOnAllPathsVisitor : public ProgramVisitor {
396public:
397 bool visitExpression(const Expression& expr) override {
398 // We can avoid processing expressions entirely.
399 return false;
400 }
401
402 bool visitStatement(const Statement& stmt) override {
403 switch (stmt.kind()) {
404 // Returns, breaks, or continues will stop the scan, so only one of these should ever be
405 // true.
406 case Statement::Kind::kReturn:
407 fFoundReturn = true;
408 return true;
409
410 case Statement::Kind::kBreak:
411 fFoundBreak = true;
412 return true;
413
414 case Statement::Kind::kContinue:
415 fFoundContinue = true;
416 return true;
417
418 case Statement::Kind::kIf: {
419 const IfStatement& i = stmt.as<IfStatement>();
420 ReturnsOnAllPathsVisitor trueVisitor;
421 ReturnsOnAllPathsVisitor falseVisitor;
422 trueVisitor.visitStatement(*i.ifTrue());
423 if (i.ifFalse()) {
424 falseVisitor.visitStatement(*i.ifFalse());
425 }
426 // If either branch leads to a break or continue, we report the entire if as
427 // containing a break or continue, since we don't know which side will be reached.
428 fFoundBreak = (trueVisitor.fFoundBreak || falseVisitor.fFoundBreak);
429 fFoundContinue = (trueVisitor.fFoundContinue || falseVisitor.fFoundContinue);
430 // On the other hand, we only want to report returns that definitely happen, so we
431 // require those to be found on both sides.
432 fFoundReturn = (trueVisitor.fFoundReturn && falseVisitor.fFoundReturn);
433 return fFoundBreak || fFoundContinue || fFoundReturn;
434 }
435 case Statement::Kind::kFor: {
436 const ForStatement& f = stmt.as<ForStatement>();
437 // We assume a for/while loop runs for at least one iteration; this isn't strictly
438 // guaranteed, but it's better to be slightly over-permissive here than to fail on
439 // reasonable code.
440 ReturnsOnAllPathsVisitor forVisitor;
441 forVisitor.visitStatement(*f.statement());
442 // A for loop that contains a break or continue is safe; it won't exit the entire
443 // function, just the loop. So we disregard those signals.
444 fFoundReturn = forVisitor.fFoundReturn;
445 return fFoundReturn;
446 }
447 case Statement::Kind::kDo: {
448 const DoStatement& d = stmt.as<DoStatement>();
449 // Do-while blocks are always entered at least once.
450 ReturnsOnAllPathsVisitor doVisitor;
451 doVisitor.visitStatement(*d.statement());
452 // A do-while loop that contains a break or continue is safe; it won't exit the
453 // entire function, just the loop. So we disregard those signals.
454 fFoundReturn = doVisitor.fFoundReturn;
455 return fFoundReturn;
456 }
457 case Statement::Kind::kBlock:
458 // Blocks are definitely entered and don't imply any additional control flow.
459 // If the block contains a break, continue or return, we want to keep that.
460 return INHERITED::visitStatement(stmt);
461
462 case Statement::Kind::kSwitch: {
463 // Switches are the most complex control flow we need to deal with; fortunately we
464 // already have good primitives for dissecting them. We need to verify that:
465 // - a default case exists, so that every possible input value is covered
466 // - every switch-case either (a) returns unconditionally, or
467 // (b) falls through to another case that does
468 const SwitchStatement& s = stmt.as<SwitchStatement>();
469 bool foundDefault = false;
470 bool fellThrough = false;
471 for (const std::unique_ptr<SwitchCase>& sc : s.cases()) {
472 // The default case is indicated by a null value. A switch without a default
473 // case cannot definitively return, as its value might not be in the cases list.
474 if (!sc->value()) {
475 foundDefault = true;
476 }
477 // Scan this switch-case for any exit (break, continue or return).
478 ReturnsOnAllPathsVisitor caseVisitor;
479 caseVisitor.visitStatement(*sc);
480
481 // If we found a break or continue, whether conditional or not, this switch case
482 // can't be called an unconditional return. Switches absorb breaks but not
483 // continues.
484 if (caseVisitor.fFoundContinue) {
485 fFoundContinue = true;
486 return false;
487 }
488 if (caseVisitor.fFoundBreak) {
489 return false;
490 }
491 // We just confirmed that there weren't any breaks or continues. If we didn't
492 // find an unconditional return either, the switch is considered fallen-through.
493 // (There might be a conditional return, but that doesn't count.)
494 fellThrough = !caseVisitor.fFoundReturn;
495 }
496
497 // If we didn't find a default case, or the very last case fell through, this switch
498 // doesn't meet our criteria.
499 if (fellThrough || !foundDefault) {
500 return false;
501 }
502
503 // We scanned the entire switch, found a default case, and every section either fell
504 // through or contained an unconditional return.
505 fFoundReturn = true;
506 return true;
507 }
508
509 case Statement::Kind::kSwitchCase:
510 // Recurse into the switch-case.
511 return INHERITED::visitStatement(stmt);
512
513 case Statement::Kind::kDiscard:
514 case Statement::Kind::kExpression:
515 case Statement::Kind::kInlineMarker:
516 case Statement::Kind::kNop:
517 case Statement::Kind::kVarDeclaration:
518 // None of these statements could contain a return.
519 break;
520 }
521
522 return false;
523 }
524
525 bool fFoundReturn = false;
526 bool fFoundBreak = false;
527 bool fFoundContinue = false;
528
529 using INHERITED = ProgramVisitor;
530};
531
John Stilesa6841be2020-08-06 14:11:56 -0400532} // namespace
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400533
534////////////////////////////////////////////////////////////////////////////////
535// Analysis
536
Brian Osman1298bc42020-06-30 13:39:35 -0400537SampleUsage Analysis::GetSampleUsage(const Program& program, const Variable& fp) {
John Stiles933abe32020-08-28 11:58:40 -0400538 MergeSampleUsageVisitor visitor(*program.fContext, fp);
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400539 return visitor.visit(program);
540}
541
Brian Osman92aac1e2020-08-05 16:48:58 -0400542bool Analysis::ReferencesBuiltin(const Program& program, int builtin) {
543 BuiltinVariableVisitor visitor(builtin);
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400544 return visitor.visit(program);
545}
546
Brian Osman92aac1e2020-08-05 16:48:58 -0400547bool Analysis::ReferencesSampleCoords(const Program& program) {
548 return Analysis::ReferencesBuiltin(program, SK_MAIN_COORDS_BUILTIN);
549}
550
551bool Analysis::ReferencesFragCoords(const Program& program) {
552 return Analysis::ReferencesBuiltin(program, SK_FRAGCOORD_BUILTIN);
553}
554
John Stiles9b9415e2020-11-23 14:48:06 -0500555int Analysis::NodeCountUpToLimit(const FunctionDefinition& function, int limit) {
556 return NodeCountVisitor{limit}.visit(*function.body());
Ethan Nicholas6e0fa402020-08-20 14:08:23 -0400557}
558
John Stiles642cde22021-02-23 14:57:01 -0500559bool Analysis::SwitchCaseContainsUnconditionalExit(Statement& stmt) {
560 return SwitchCaseContainsExit{/*conditionalExits=*/false}.visitStatement(stmt);
561}
562
563bool Analysis::SwitchCaseContainsConditionalExit(Statement& stmt) {
564 return SwitchCaseContainsExit{/*conditionalExits=*/true}.visitStatement(stmt);
565}
566
Brian Osman010ce6a2020-10-19 16:34:10 -0400567std::unique_ptr<ProgramUsage> Analysis::GetUsage(const Program& program) {
568 auto usage = std::make_unique<ProgramUsage>();
569 ProgramUsageVisitor addRefs(usage.get(), /*delta=*/+1);
570 addRefs.visit(program);
571 return usage;
572}
573
Brian Osman0006ad02020-11-18 15:38:39 -0500574std::unique_ptr<ProgramUsage> Analysis::GetUsage(const LoadedModule& module) {
575 auto usage = std::make_unique<ProgramUsage>();
576 ProgramUsageVisitor addRefs(usage.get(), /*delta=*/+1);
577 for (const auto& element : module.fElements) {
578 addRefs.visitProgramElement(*element);
579 }
580 return usage;
581}
582
Brian Osman010ce6a2020-10-19 16:34:10 -0400583ProgramUsage::VariableCounts ProgramUsage::get(const Variable& v) const {
584 VariableCounts result = { 0, v.initialValue() ? 1 : 0 };
585 if (const VariableCounts* counts = fVariableCounts.find(&v)) {
586 result.fRead += counts->fRead;
587 result.fWrite += counts->fWrite;
588 }
589 return result;
590}
591
592bool ProgramUsage::isDead(const Variable& v) const {
593 const Modifiers& modifiers = v.modifiers();
594 VariableCounts counts = this->get(v);
595 if ((v.storage() != Variable::Storage::kLocal && counts.fRead) ||
596 (modifiers.fFlags & (Modifiers::kIn_Flag | Modifiers::kOut_Flag | Modifiers::kUniform_Flag |
597 Modifiers::kVarying_Flag))) {
598 return false;
599 }
Brian Osman9cb3f982021-02-18 12:44:57 -0500600 return !counts.fWrite || !counts.fRead;
Brian Osman010ce6a2020-10-19 16:34:10 -0400601}
602
603int ProgramUsage::get(const FunctionDeclaration& f) const {
604 const int* count = fCallCounts.find(&f);
605 return count ? *count : 0;
606}
607
608void ProgramUsage::replace(const Expression* oldExpr, const Expression* newExpr) {
609 if (oldExpr) {
610 ProgramUsageVisitor subRefs(this, /*delta=*/-1);
611 subRefs.visitExpression(*oldExpr);
612 }
613 if (newExpr) {
614 ProgramUsageVisitor addRefs(this, /*delta=*/+1);
615 addRefs.visitExpression(*newExpr);
616 }
617}
618
619void ProgramUsage::add(const Statement* stmt) {
620 ProgramUsageVisitor addRefs(this, /*delta=*/+1);
621 addRefs.visitStatement(*stmt);
622}
623
624void ProgramUsage::remove(const Expression* expr) {
625 ProgramUsageVisitor subRefs(this, /*delta=*/-1);
626 subRefs.visitExpression(*expr);
627}
628
629void ProgramUsage::remove(const Statement* stmt) {
630 ProgramUsageVisitor subRefs(this, /*delta=*/-1);
631 subRefs.visitStatement(*stmt);
632}
633
634void ProgramUsage::remove(const ProgramElement& element) {
635 ProgramUsageVisitor subRefs(this, /*delta=*/-1);
636 subRefs.visitProgramElement(element);
Brian Osman2e25ff42020-10-15 10:32:04 -0400637}
638
Ethan Nicholas765d2fe2020-08-26 08:29:55 -0400639bool Analysis::StatementWritesToVariable(const Statement& stmt, const Variable& var) {
640 return VariableWriteVisitor(&var).visit(stmt);
641}
642
John Stilesb21fac22020-12-04 15:36:49 -0500643bool Analysis::IsAssignable(Expression& expr, AssignmentInfo* info, ErrorReporter* errors) {
John Stilesa976da72020-09-25 23:06:26 -0400644 TrivialErrorReporter trivialErrors;
John Stilesb21fac22020-12-04 15:36:49 -0500645 return IsAssignableVisitor{errors ? errors : &trivialErrors}.visit(expr, info);
John Stilesdce4d3e2020-09-25 14:35:13 -0400646}
647
John Stiles47c0a742021-02-09 09:30:35 -0500648void Analysis::UpdateRefKind(Expression* expr, VariableRefKind refKind) {
649 class RefKindWriter : public ProgramWriter {
650 public:
651 RefKindWriter(VariableReference::RefKind refKind) : fRefKind(refKind) {}
652
653 bool visitExpression(Expression& expr) override {
654 if (expr.is<VariableReference>()) {
655 expr.as<VariableReference>().setRefKind(fRefKind);
656 }
657 return INHERITED::visitExpression(expr);
658 }
659
660 private:
661 VariableReference::RefKind fRefKind;
662
663 using INHERITED = ProgramWriter;
664 };
665
666 RefKindWriter{refKind}.visitExpression(*expr);
667}
668
John Stiles516704b2021-02-26 15:01:57 -0500669bool Analysis::MakeAssignmentExpr(Expression* expr,
670 VariableReference::RefKind kind,
671 ErrorReporter* errors) {
672 Analysis::AssignmentInfo info;
673 if (!Analysis::IsAssignable(*expr, &info, errors)) {
674 return false;
675 }
676 if (!info.fAssignedVar) {
677 errors->error(expr->fOffset, "can't assign to expression '" + expr->description() + "'");
678 return false;
679 }
680 info.fAssignedVar->setRefKind(kind);
681 return true;
682}
683
John Stilesc30fbca2020-11-19 16:25:49 -0500684bool Analysis::IsTrivialExpression(const Expression& expr) {
685 return expr.is<IntLiteral>() ||
686 expr.is<FloatLiteral>() ||
687 expr.is<BoolLiteral>() ||
688 expr.is<VariableReference>() ||
689 (expr.is<Swizzle>() &&
690 IsTrivialExpression(*expr.as<Swizzle>().base())) ||
691 (expr.is<FieldAccess>() &&
692 IsTrivialExpression(*expr.as<FieldAccess>().base())) ||
693 (expr.is<Constructor>() &&
694 expr.as<Constructor>().arguments().size() == 1 &&
695 IsTrivialExpression(*expr.as<Constructor>().arguments().front())) ||
696 (expr.is<Constructor>() &&
697 expr.isConstantOrUniform()) ||
698 (expr.is<IndexExpression>() &&
699 expr.as<IndexExpression>().index()->is<IntLiteral>() &&
700 IsTrivialExpression(*expr.as<IndexExpression>().base()));
701}
702
John Stiles5676c572021-03-08 17:10:52 -0500703bool Analysis::IsSameExpressionTree(const Expression& left, const Expression& right) {
John Stiles95d0bad2021-03-01 17:02:28 -0500704 if (left.kind() != right.kind() || left.type() != right.type()) {
705 return false;
706 }
707
John Stiles5676c572021-03-08 17:10:52 -0500708 // This isn't a fully exhaustive list of expressions by any stretch of the imagination; for
709 // instance, `x[y+1] = x[y+1]` isn't detected because we don't look at BinaryExpressions.
710 // Since this is intended to be used for optimization purposes, handling the common cases is
711 // sufficient.
John Stiles95d0bad2021-03-01 17:02:28 -0500712 switch (left.kind()) {
713 case Expression::Kind::kIntLiteral:
714 return left.as<IntLiteral>().value() == right.as<IntLiteral>().value();
715
John Stiles5676c572021-03-08 17:10:52 -0500716 case Expression::Kind::kFloatLiteral:
717 return left.as<FloatLiteral>().value() == right.as<FloatLiteral>().value();
718
719 case Expression::Kind::kBoolLiteral:
720 return left.as<BoolLiteral>().value() == right.as<BoolLiteral>().value();
721
722 case Expression::Kind::kConstructor: {
723 const Constructor& leftCtor = left.as<Constructor>();
724 const Constructor& rightCtor = right.as<Constructor>();
725 if (leftCtor.arguments().count() != rightCtor.arguments().count()) {
726 return false;
727 }
728 for (int index = 0; index < leftCtor.arguments().count(); ++index) {
729 if (!IsSameExpressionTree(*leftCtor.arguments()[index],
730 *rightCtor.arguments()[index])) {
731 return false;
732 }
733 }
734 return true;
735 }
John Stiles95d0bad2021-03-01 17:02:28 -0500736 case Expression::Kind::kFieldAccess:
737 return left.as<FieldAccess>().fieldIndex() == right.as<FieldAccess>().fieldIndex() &&
John Stiles5676c572021-03-08 17:10:52 -0500738 IsSameExpressionTree(*left.as<FieldAccess>().base(),
739 *right.as<FieldAccess>().base());
John Stiles95d0bad2021-03-01 17:02:28 -0500740
741 case Expression::Kind::kIndex:
John Stiles5676c572021-03-08 17:10:52 -0500742 return IsSameExpressionTree(*left.as<IndexExpression>().index(),
743 *right.as<IndexExpression>().index()) &&
744 IsSameExpressionTree(*left.as<IndexExpression>().base(),
745 *right.as<IndexExpression>().base());
John Stiles95d0bad2021-03-01 17:02:28 -0500746
747 case Expression::Kind::kSwizzle:
748 return left.as<Swizzle>().components() == right.as<Swizzle>().components() &&
John Stiles5676c572021-03-08 17:10:52 -0500749 IsSameExpressionTree(*left.as<Swizzle>().base(), *right.as<Swizzle>().base());
John Stiles95d0bad2021-03-01 17:02:28 -0500750
751 case Expression::Kind::kVariableReference:
752 return left.as<VariableReference>().variable() ==
753 right.as<VariableReference>().variable();
754
755 default:
756 return false;
757 }
758}
759
John Stiles232b4ce2021-03-01 22:14:22 -0500760static const char* invalid_for_ES2(int offset,
761 const Statement* loopInitializer,
762 const Expression* loopTest,
763 const Expression* loopNext,
764 const Statement* loopStatement,
Brian Osman77ba8102021-01-12 17:15:30 -0500765 Analysis::UnrollableLoopInfo& loopInfo) {
766 auto getConstant = [&](const std::unique_ptr<Expression>& expr, double* val) {
767 if (!expr->isCompileTimeConstant()) {
768 return false;
769 }
Brian Osman6c7910e2021-01-14 09:50:52 -0500770 if (!expr->type().isNumber()) {
Brian Osman77ba8102021-01-12 17:15:30 -0500771 SkDEBUGFAIL("unexpected constant type");
772 return false;
773 }
774
775 *val = expr->type().isInteger() ? static_cast<double>(expr->getConstantInt())
776 : static_cast<double>(expr->getConstantFloat());
777 return true;
778 };
779
780 //
781 // init_declaration has the form: type_specifier identifier = constant_expression
782 //
John Stiles232b4ce2021-03-01 22:14:22 -0500783 if (!loopInitializer) {
Brian Osman77ba8102021-01-12 17:15:30 -0500784 return "missing init declaration";
785 }
John Stiles232b4ce2021-03-01 22:14:22 -0500786 if (!loopInitializer->is<VarDeclaration>()) {
Brian Osman77ba8102021-01-12 17:15:30 -0500787 return "invalid init declaration";
788 }
John Stiles232b4ce2021-03-01 22:14:22 -0500789 const VarDeclaration& initDecl = loopInitializer->as<VarDeclaration>();
Brian Osman6c7910e2021-01-14 09:50:52 -0500790 if (!initDecl.baseType().isNumber()) {
Brian Osman77ba8102021-01-12 17:15:30 -0500791 return "invalid type for loop index";
792 }
793 if (initDecl.arraySize() != 0) {
794 return "invalid type for loop index";
795 }
796 if (!initDecl.value()) {
797 return "missing loop index initializer";
798 }
799 if (!getConstant(initDecl.value(), &loopInfo.fStart)) {
800 return "loop index initializer must be a constant expression";
801 }
802
803 loopInfo.fIndex = &initDecl.var();
804
805 auto is_loop_index = [&](const std::unique_ptr<Expression>& expr) {
806 return expr->is<VariableReference>() &&
807 expr->as<VariableReference>().variable() == loopInfo.fIndex;
808 };
809
810 //
811 // condition has the form: loop_index relational_operator constant_expression
812 //
John Stiles232b4ce2021-03-01 22:14:22 -0500813 if (!loopTest) {
Brian Osman77ba8102021-01-12 17:15:30 -0500814 return "missing condition";
815 }
John Stiles232b4ce2021-03-01 22:14:22 -0500816 if (!loopTest->is<BinaryExpression>()) {
Brian Osman77ba8102021-01-12 17:15:30 -0500817 return "invalid condition";
818 }
John Stiles232b4ce2021-03-01 22:14:22 -0500819 const BinaryExpression& cond = loopTest->as<BinaryExpression>();
Brian Osman77ba8102021-01-12 17:15:30 -0500820 if (!is_loop_index(cond.left())) {
821 return "expected loop index on left hand side of condition";
822 }
823 // relational_operator is one of: > >= < <= == or !=
John Stiles45990502021-02-16 10:55:27 -0500824 switch (cond.getOperator().kind()) {
Brian Osman77ba8102021-01-12 17:15:30 -0500825 case Token::Kind::TK_GT:
826 case Token::Kind::TK_GTEQ:
827 case Token::Kind::TK_LT:
828 case Token::Kind::TK_LTEQ:
829 case Token::Kind::TK_EQEQ:
830 case Token::Kind::TK_NEQ:
831 break;
832 default:
833 return "invalid relational operator";
834 }
835 double loopEnd = 0;
836 if (!getConstant(cond.right(), &loopEnd)) {
837 return "loop index must be compared with a constant expression";
838 }
839
840 //
841 // expression has one of the following forms:
842 // loop_index++
843 // loop_index--
844 // loop_index += constant_expression
845 // loop_index -= constant_expression
846 // The spec doesn't mention prefix increment and decrement, but there is some consensus that
847 // it's an oversight, so we allow those as well.
848 //
John Stiles232b4ce2021-03-01 22:14:22 -0500849 if (!loopNext) {
Brian Osman77ba8102021-01-12 17:15:30 -0500850 return "missing loop expression";
851 }
John Stiles232b4ce2021-03-01 22:14:22 -0500852 switch (loopNext->kind()) {
Brian Osman77ba8102021-01-12 17:15:30 -0500853 case Expression::Kind::kBinary: {
John Stiles232b4ce2021-03-01 22:14:22 -0500854 const BinaryExpression& next = loopNext->as<BinaryExpression>();
Brian Osman77ba8102021-01-12 17:15:30 -0500855 if (!is_loop_index(next.left())) {
856 return "expected loop index in loop expression";
857 }
858 if (!getConstant(next.right(), &loopInfo.fDelta)) {
859 return "loop index must be modified by a constant expression";
860 }
John Stiles45990502021-02-16 10:55:27 -0500861 switch (next.getOperator().kind()) {
Brian Osman77ba8102021-01-12 17:15:30 -0500862 case Token::Kind::TK_PLUSEQ: break;
863 case Token::Kind::TK_MINUSEQ: loopInfo.fDelta = -loopInfo.fDelta; break;
864 default:
865 return "invalid operator in loop expression";
866 }
867 } break;
868 case Expression::Kind::kPrefix: {
John Stiles232b4ce2021-03-01 22:14:22 -0500869 const PrefixExpression& next = loopNext->as<PrefixExpression>();
Brian Osman77ba8102021-01-12 17:15:30 -0500870 if (!is_loop_index(next.operand())) {
871 return "expected loop index in loop expression";
872 }
John Stiles45990502021-02-16 10:55:27 -0500873 switch (next.getOperator().kind()) {
Brian Osman77ba8102021-01-12 17:15:30 -0500874 case Token::Kind::TK_PLUSPLUS: loopInfo.fDelta = 1; break;
875 case Token::Kind::TK_MINUSMINUS: loopInfo.fDelta = -1; break;
876 default:
877 return "invalid operator in loop expression";
878 }
879 } break;
880 case Expression::Kind::kPostfix: {
John Stiles232b4ce2021-03-01 22:14:22 -0500881 const PostfixExpression& next = loopNext->as<PostfixExpression>();
Brian Osman77ba8102021-01-12 17:15:30 -0500882 if (!is_loop_index(next.operand())) {
883 return "expected loop index in loop expression";
884 }
John Stiles45990502021-02-16 10:55:27 -0500885 switch (next.getOperator().kind()) {
Brian Osman77ba8102021-01-12 17:15:30 -0500886 case Token::Kind::TK_PLUSPLUS: loopInfo.fDelta = 1; break;
887 case Token::Kind::TK_MINUSMINUS: loopInfo.fDelta = -1; break;
888 default:
889 return "invalid operator in loop expression";
890 }
891 } break;
892 default:
893 return "invalid loop expression";
894 }
895
896 //
897 // Within the body of the loop, the loop index is not statically assigned to, nor is it used as
898 // argument to a function 'out' or 'inout' parameter.
899 //
John Stiles232b4ce2021-03-01 22:14:22 -0500900 if (Analysis::StatementWritesToVariable(*loopStatement, initDecl.var())) {
Brian Osman77ba8102021-01-12 17:15:30 -0500901 return "loop index must not be modified within body of the loop";
902 }
903
904 // Finally, compute the iteration count, based on the bounds, and the termination operator.
905 constexpr int kMaxUnrollableLoopLength = 128;
906 loopInfo.fCount = 0;
907
908 double val = loopInfo.fStart;
909 auto evalCond = [&]() {
John Stiles45990502021-02-16 10:55:27 -0500910 switch (cond.getOperator().kind()) {
Brian Osman77ba8102021-01-12 17:15:30 -0500911 case Token::Kind::TK_GT: return val > loopEnd;
912 case Token::Kind::TK_GTEQ: return val >= loopEnd;
913 case Token::Kind::TK_LT: return val < loopEnd;
914 case Token::Kind::TK_LTEQ: return val <= loopEnd;
915 case Token::Kind::TK_EQEQ: return val == loopEnd;
916 case Token::Kind::TK_NEQ: return val != loopEnd;
917 default: SkUNREACHABLE;
918 }
919 };
920
921 for (loopInfo.fCount = 0; loopInfo.fCount <= kMaxUnrollableLoopLength; ++loopInfo.fCount) {
922 if (!evalCond()) {
923 break;
924 }
925 val += loopInfo.fDelta;
926 }
927
928 if (loopInfo.fCount > kMaxUnrollableLoopLength) {
929 return "loop must guarantee termination in fewer iterations";
930 }
931
932 return nullptr; // All checks pass
933}
934
John Stiles232b4ce2021-03-01 22:14:22 -0500935bool Analysis::ForLoopIsValidForES2(int offset,
936 const Statement* loopInitializer,
937 const Expression* loopTest,
938 const Expression* loopNext,
939 const Statement* loopStatement,
Brian Osman77ba8102021-01-12 17:15:30 -0500940 Analysis::UnrollableLoopInfo* outLoopInfo,
941 ErrorReporter* errors) {
942 UnrollableLoopInfo ignored,
943 *loopInfo = outLoopInfo ? outLoopInfo : &ignored;
John Stiles232b4ce2021-03-01 22:14:22 -0500944 if (const char* msg = invalid_for_ES2(
945 offset, loopInitializer, loopTest, loopNext, loopStatement, *loopInfo)) {
Brian Osman77ba8102021-01-12 17:15:30 -0500946 if (errors) {
John Stiles232b4ce2021-03-01 22:14:22 -0500947 errors->error(offset, msg);
Brian Osman77ba8102021-01-12 17:15:30 -0500948 }
949 return false;
950 }
951 return true;
952}
953
Brian Osman7b361492021-02-25 11:25:30 -0500954// Checks for ES2 constant-expression rules, and (optionally) constant-index-expression rules
955// (if loopIndices is non-nullptr)
956class ConstantExpressionVisitor : public ProgramVisitor {
Brian Osmanea485e52021-01-15 13:20:32 -0500957public:
Brian Osman7b361492021-02-25 11:25:30 -0500958 ConstantExpressionVisitor(const std::set<const Variable*>* loopIndices)
Brian Osmanea485e52021-01-15 13:20:32 -0500959 : fLoopIndices(loopIndices) {}
960
961 bool visitExpression(const Expression& e) override {
962 // A constant-(index)-expression is one of...
963 switch (e.kind()) {
964 // ... a literal value
965 case Expression::Kind::kBoolLiteral:
966 case Expression::Kind::kIntLiteral:
967 case Expression::Kind::kFloatLiteral:
968 return false;
969
John Stiles532138c2021-03-04 16:29:22 -0500970 // ... settings can appear in fragment processors; they will resolve when compiled
971 case Expression::Kind::kSetting:
972 return false;
973
Brian Osman7b361492021-02-25 11:25:30 -0500974 // ... a global or local variable qualified as 'const', excluding function parameters.
975 // ... loop indices as defined in section 4. [constant-index-expression]
976 case Expression::Kind::kVariableReference: {
977 const Variable* v = e.as<VariableReference>().variable();
978 if ((v->storage() == Variable::Storage::kGlobal ||
979 v->storage() == Variable::Storage::kLocal) &&
980 (v->modifiers().fFlags & Modifiers::kConst_Flag)) {
981 return false;
982 }
983 return !fLoopIndices || fLoopIndices->find(v) == fLoopIndices->end();
984 }
Brian Osmanea485e52021-01-15 13:20:32 -0500985
986 // ... expressions composed of both of the above
987 case Expression::Kind::kBinary:
988 case Expression::Kind::kConstructor:
989 case Expression::Kind::kFieldAccess:
990 case Expression::Kind::kIndex:
991 case Expression::Kind::kPrefix:
992 case Expression::Kind::kPostfix:
993 case Expression::Kind::kSwizzle:
994 case Expression::Kind::kTernary:
995 return INHERITED::visitExpression(e);
996
Brian Osman7b361492021-02-25 11:25:30 -0500997 // These are completely disallowed in SkSL constant-(index)-expressions. GLSL allows
Brian Osmanea485e52021-01-15 13:20:32 -0500998 // calls to built-in functions where the arguments are all constant-expressions, but
999 // we don't guarantee that behavior. (skbug.com/10835)
1000 case Expression::Kind::kExternalFunctionCall:
1001 case Expression::Kind::kFunctionCall:
1002 return true;
1003
1004 // These should never appear in final IR
1005 case Expression::Kind::kDefined:
1006 case Expression::Kind::kExternalFunctionReference:
1007 case Expression::Kind::kFunctionReference:
Brian Osmanea485e52021-01-15 13:20:32 -05001008 case Expression::Kind::kTypeReference:
1009 default:
1010 SkDEBUGFAIL("Unexpected expression type");
1011 return true;
1012 }
1013 }
1014
1015private:
1016 const std::set<const Variable*>* fLoopIndices;
1017 using INHERITED = ProgramVisitor;
1018};
1019
1020class ES2IndexingVisitor : public ProgramVisitor {
1021public:
1022 ES2IndexingVisitor(ErrorReporter& errors) : fErrors(errors) {}
1023
1024 bool visitStatement(const Statement& s) override {
1025 if (s.is<ForStatement>()) {
1026 const ForStatement& f = s.as<ForStatement>();
1027 SkASSERT(f.initializer() && f.initializer()->is<VarDeclaration>());
1028 const Variable* var = &f.initializer()->as<VarDeclaration>().var();
1029 auto [iter, inserted] = fLoopIndices.insert(var);
1030 SkASSERT(inserted);
1031 bool result = this->visitStatement(*f.statement());
1032 fLoopIndices.erase(iter);
1033 return result;
1034 }
1035 return INHERITED::visitStatement(s);
1036 }
1037
1038 bool visitExpression(const Expression& e) override {
1039 if (e.is<IndexExpression>()) {
1040 const IndexExpression& i = e.as<IndexExpression>();
Brian Osman7b361492021-02-25 11:25:30 -05001041 ConstantExpressionVisitor indexerInvalid(&fLoopIndices);
Brian Osmanea485e52021-01-15 13:20:32 -05001042 if (indexerInvalid.visitExpression(*i.index())) {
1043 fErrors.error(i.fOffset, "index expression must be constant");
1044 return true;
1045 }
1046 }
1047 return INHERITED::visitExpression(e);
1048 }
1049
1050 using ProgramVisitor::visitProgramElement;
1051
1052private:
1053 ErrorReporter& fErrors;
1054 std::set<const Variable*> fLoopIndices;
1055 using INHERITED = ProgramVisitor;
1056};
1057
1058
1059void Analysis::ValidateIndexingForES2(const ProgramElement& pe, ErrorReporter& errors) {
1060 ES2IndexingVisitor visitor(errors);
1061 visitor.visitProgramElement(pe);
1062}
1063
Brian Osman7b361492021-02-25 11:25:30 -05001064bool Analysis::IsConstantExpression(const Expression& expr) {
1065 ConstantExpressionVisitor visitor(/*loopIndices=*/nullptr);
1066 return !visitor.visitExpression(expr);
1067}
1068
John Stilesb3dcbb12021-03-04 16:00:20 -05001069bool Analysis::CanExitWithoutReturningValue(const FunctionDefinition& funcDef) {
1070 ReturnsOnAllPathsVisitor visitor;
1071 visitor.visitStatement(*funcDef.body());
1072 return !visitor.fFoundReturn;
1073}
1074
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001075////////////////////////////////////////////////////////////////////////////////
1076// ProgramVisitor
1077
Brian Osman133724c2020-10-28 14:14:39 -04001078bool ProgramVisitor::visit(const Program& program) {
1079 for (const ProgramElement* pe : program.elements()) {
Brian Osman1179fcf2020-10-08 16:04:40 -04001080 if (this->visitProgramElement(*pe)) {
John Stiles933abe32020-08-28 11:58:40 -04001081 return true;
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001082 }
1083 }
John Stiles933abe32020-08-28 11:58:40 -04001084 return false;
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001085}
1086
John Stiles70b82422020-09-30 10:55:12 -04001087template <typename PROG, typename EXPR, typename STMT, typename ELEM>
1088bool TProgramVisitor<PROG, EXPR, STMT, ELEM>::visitExpression(EXPR e) {
1089 switch (e.kind()) {
Ethan Nicholase6592142020-09-08 10:22:09 -04001090 case Expression::Kind::kBoolLiteral:
1091 case Expression::Kind::kDefined:
Brian Osmanbe0b3b72021-01-06 14:27:35 -05001092 case Expression::Kind::kExternalFunctionReference:
Ethan Nicholase6592142020-09-08 10:22:09 -04001093 case Expression::Kind::kFloatLiteral:
1094 case Expression::Kind::kFunctionReference:
1095 case Expression::Kind::kIntLiteral:
Ethan Nicholase6592142020-09-08 10:22:09 -04001096 case Expression::Kind::kSetting:
1097 case Expression::Kind::kTypeReference:
1098 case Expression::Kind::kVariableReference:
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001099 // Leaf expressions return false
1100 return false;
John Stiles70b82422020-09-30 10:55:12 -04001101
Ethan Nicholase6592142020-09-08 10:22:09 -04001102 case Expression::Kind::kBinary: {
John Stiles70b82422020-09-30 10:55:12 -04001103 auto& b = e.template as<BinaryExpression>();
John Stiles2d4f9592020-10-30 10:29:12 -04001104 return (b.left() && this->visitExpression(*b.left())) ||
1105 (b.right() && this->visitExpression(*b.right()));
John Stiles70b82422020-09-30 10:55:12 -04001106 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001107 case Expression::Kind::kConstructor: {
John Stiles70b82422020-09-30 10:55:12 -04001108 auto& c = e.template as<Constructor>();
1109 for (auto& arg : c.arguments()) {
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001110 if (this->visitExpression(*arg)) { return true; }
1111 }
John Stiles70b82422020-09-30 10:55:12 -04001112 return false;
1113 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001114 case Expression::Kind::kExternalFunctionCall: {
John Stiles70b82422020-09-30 10:55:12 -04001115 auto& c = e.template as<ExternalFunctionCall>();
Ethan Nicholas6e86ec92020-09-30 14:29:56 -04001116 for (auto& arg : c.arguments()) {
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001117 if (this->visitExpression(*arg)) { return true; }
1118 }
John Stiles70b82422020-09-30 10:55:12 -04001119 return false;
1120 }
John Stilesd7ab4502020-09-24 22:41:00 -04001121 case Expression::Kind::kFieldAccess:
Ethan Nicholas7a95b202020-10-09 11:55:40 -04001122 return this->visitExpression(*e.template as<FieldAccess>().base());
John Stiles70b82422020-09-30 10:55:12 -04001123
Ethan Nicholase6592142020-09-08 10:22:09 -04001124 case Expression::Kind::kFunctionCall: {
John Stiles70b82422020-09-30 10:55:12 -04001125 auto& c = e.template as<FunctionCall>();
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001126 for (auto& arg : c.arguments()) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001127 if (arg && this->visitExpression(*arg)) { return true; }
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001128 }
John Stiles70b82422020-09-30 10:55:12 -04001129 return false;
1130 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001131 case Expression::Kind::kIndex: {
John Stiles70b82422020-09-30 10:55:12 -04001132 auto& i = e.template as<IndexExpression>();
Ethan Nicholas2a4952d2020-10-08 15:35:56 -04001133 return this->visitExpression(*i.base()) || this->visitExpression(*i.index());
John Stiles70b82422020-09-30 10:55:12 -04001134 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001135 case Expression::Kind::kPostfix:
Ethan Nicholas444ccc62020-10-09 10:16:22 -04001136 return this->visitExpression(*e.template as<PostfixExpression>().operand());
John Stiles70b82422020-09-30 10:55:12 -04001137
Ethan Nicholase6592142020-09-08 10:22:09 -04001138 case Expression::Kind::kPrefix:
Ethan Nicholas444ccc62020-10-09 10:16:22 -04001139 return this->visitExpression(*e.template as<PrefixExpression>().operand());
John Stiles70b82422020-09-30 10:55:12 -04001140
Brian Osman010ce6a2020-10-19 16:34:10 -04001141 case Expression::Kind::kSwizzle: {
1142 auto& s = e.template as<Swizzle>();
1143 return s.base() && this->visitExpression(*s.base());
1144 }
John Stiles70b82422020-09-30 10:55:12 -04001145
Ethan Nicholase6592142020-09-08 10:22:09 -04001146 case Expression::Kind::kTernary: {
John Stiles70b82422020-09-30 10:55:12 -04001147 auto& t = e.template as<TernaryExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -04001148 return this->visitExpression(*t.test()) ||
1149 (t.ifTrue() && this->visitExpression(*t.ifTrue())) ||
1150 (t.ifFalse() && this->visitExpression(*t.ifFalse()));
John Stiles70b82422020-09-30 10:55:12 -04001151 }
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001152 default:
1153 SkUNREACHABLE;
1154 }
1155}
1156
John Stiles70b82422020-09-30 10:55:12 -04001157template <typename PROG, typename EXPR, typename STMT, typename ELEM>
1158bool TProgramVisitor<PROG, EXPR, STMT, ELEM>::visitStatement(STMT s) {
1159 switch (s.kind()) {
Ethan Nicholase6592142020-09-08 10:22:09 -04001160 case Statement::Kind::kBreak:
1161 case Statement::Kind::kContinue:
1162 case Statement::Kind::kDiscard:
John Stiles98c1f822020-09-09 14:18:53 -04001163 case Statement::Kind::kInlineMarker:
Ethan Nicholase6592142020-09-08 10:22:09 -04001164 case Statement::Kind::kNop:
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001165 // Leaf statements just return false
1166 return false;
John Stiles70b82422020-09-30 10:55:12 -04001167
Ethan Nicholase6592142020-09-08 10:22:09 -04001168 case Statement::Kind::kBlock:
John Stiles70b82422020-09-30 10:55:12 -04001169 for (auto& stmt : s.template as<Block>().children()) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001170 if (stmt && this->visitStatement(*stmt)) {
Ethan Nicholas7bd60432020-09-25 14:31:59 -04001171 return true;
1172 }
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001173 }
1174 return false;
John Stiles70b82422020-09-30 10:55:12 -04001175
John Stilesa0e56e32021-03-03 13:14:37 -05001176 case Statement::Kind::kSwitchCase: {
1177 auto& sc = s.template as<SwitchCase>();
1178 if (sc.value() && this->visitExpression(*sc.value())) {
1179 return true;
1180 }
1181 for (auto& stmt : sc.statements()) {
1182 if (stmt && this->visitStatement(*stmt)) {
1183 return true;
1184 }
1185 }
1186 return false;
1187 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001188 case Statement::Kind::kDo: {
John Stiles70b82422020-09-30 10:55:12 -04001189 auto& d = s.template as<DoStatement>();
1190 return this->visitExpression(*d.test()) || this->visitStatement(*d.statement());
1191 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001192 case Statement::Kind::kExpression:
John Stiles70b82422020-09-30 10:55:12 -04001193 return this->visitExpression(*s.template as<ExpressionStatement>().expression());
1194
Ethan Nicholase6592142020-09-08 10:22:09 -04001195 case Statement::Kind::kFor: {
John Stiles70b82422020-09-30 10:55:12 -04001196 auto& f = s.template as<ForStatement>();
Ethan Nicholas0d31ed52020-10-05 14:47:09 -04001197 return (f.initializer() && this->visitStatement(*f.initializer())) ||
1198 (f.test() && this->visitExpression(*f.test())) ||
1199 (f.next() && this->visitExpression(*f.next())) ||
1200 this->visitStatement(*f.statement());
John Stiles70b82422020-09-30 10:55:12 -04001201 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001202 case Statement::Kind::kIf: {
John Stiles70b82422020-09-30 10:55:12 -04001203 auto& i = s.template as<IfStatement>();
Brian Osman5567a602020-10-27 09:52:39 -04001204 return (i.test() && this->visitExpression(*i.test())) ||
Brian Osman010ce6a2020-10-19 16:34:10 -04001205 (i.ifTrue() && this->visitStatement(*i.ifTrue())) ||
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001206 (i.ifFalse() && this->visitStatement(*i.ifFalse()));
John Stiles70b82422020-09-30 10:55:12 -04001207 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001208 case Statement::Kind::kReturn: {
John Stiles70b82422020-09-30 10:55:12 -04001209 auto& r = s.template as<ReturnStatement>();
Ethan Nicholas2a4952d2020-10-08 15:35:56 -04001210 return r.expression() && this->visitExpression(*r.expression());
John Stiles70b82422020-09-30 10:55:12 -04001211 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001212 case Statement::Kind::kSwitch: {
John Stiles70b82422020-09-30 10:55:12 -04001213 auto& sw = s.template as<SwitchStatement>();
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001214 if (this->visitExpression(*sw.value())) {
John Stiles70b82422020-09-30 10:55:12 -04001215 return true;
1216 }
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001217 for (const auto& c : sw.cases()) {
John Stilesa0e56e32021-03-03 13:14:37 -05001218 if (this->visitStatement(*c)) {
John Stiles70b82422020-09-30 10:55:12 -04001219 return true;
1220 }
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001221 }
John Stiles70b82422020-09-30 10:55:12 -04001222 return false;
1223 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001224 case Statement::Kind::kVarDeclaration: {
John Stiles70b82422020-09-30 10:55:12 -04001225 auto& v = s.template as<VarDeclaration>();
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04001226 return v.value() && this->visitExpression(*v.value());
John Stiles70b82422020-09-30 10:55:12 -04001227 }
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001228 default:
1229 SkUNREACHABLE;
1230 }
1231}
1232
John Stiles70b82422020-09-30 10:55:12 -04001233template <typename PROG, typename EXPR, typename STMT, typename ELEM>
1234bool TProgramVisitor<PROG, EXPR, STMT, ELEM>::visitProgramElement(ELEM pe) {
1235 switch (pe.kind()) {
Ethan Nicholase6592142020-09-08 10:22:09 -04001236 case ProgramElement::Kind::kEnum:
1237 case ProgramElement::Kind::kExtension:
John Stiles569249b2020-11-03 12:18:22 -05001238 case ProgramElement::Kind::kFunctionPrototype:
John Stilesd39aec02020-12-03 10:42:26 -05001239 case ProgramElement::Kind::kInterfaceBlock:
Ethan Nicholase6592142020-09-08 10:22:09 -04001240 case ProgramElement::Kind::kModifiers:
1241 case ProgramElement::Kind::kSection:
John Stilesdc75a972020-11-25 16:24:55 -05001242 case ProgramElement::Kind::kStructDefinition:
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001243 // Leaf program elements just return false by default
1244 return false;
John Stiles70b82422020-09-30 10:55:12 -04001245
Ethan Nicholase6592142020-09-08 10:22:09 -04001246 case ProgramElement::Kind::kFunction:
Ethan Nicholas0a5d0962020-10-14 13:33:18 -04001247 return this->visitStatement(*pe.template as<FunctionDefinition>().body());
John Stiles70b82422020-09-30 10:55:12 -04001248
Brian Osmanc0213602020-10-06 14:43:32 -04001249 case ProgramElement::Kind::kGlobalVar:
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04001250 if (this->visitStatement(*pe.template as<GlobalVarDeclaration>().declaration())) {
Brian Osmanc0213602020-10-06 14:43:32 -04001251 return true;
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001252 }
1253 return false;
John Stiles70b82422020-09-30 10:55:12 -04001254
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001255 default:
1256 SkUNREACHABLE;
1257 }
1258}
1259
John Stiles70b82422020-09-30 10:55:12 -04001260template class TProgramVisitor<const Program&, const Expression&,
1261 const Statement&, const ProgramElement&>;
1262template class TProgramVisitor<Program&, Expression&, Statement&, ProgramElement&>;
1263
John Stilesa6841be2020-08-06 14:11:56 -04001264} // namespace SkSL