• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
10 #include "include/private/SkFloatingPoint.h"
11 #include "include/private/SkSLModifiers.h"
12 #include "include/private/SkSLProgramElement.h"
13 #include "include/private/SkSLSampleUsage.h"
14 #include "include/private/SkSLStatement.h"
15 #include "include/sksl/SkSLErrorReporter.h"
16 #include "src/core/SkSafeMath.h"
17 #include "src/sksl/SkSLCompiler.h"
18 #include "src/sksl/SkSLConstantFolder.h"
19 #include "src/sksl/analysis/SkSLProgramVisitor.h"
20 #include "src/sksl/ir/SkSLExpression.h"
21 #include "src/sksl/ir/SkSLProgram.h"
22 #include "src/sksl/transform/SkSLProgramWriter.h"
23 
24 // ProgramElements
25 #include "src/sksl/ir/SkSLExtension.h"
26 #include "src/sksl/ir/SkSLFunctionDefinition.h"
27 #include "src/sksl/ir/SkSLInterfaceBlock.h"
28 #include "src/sksl/ir/SkSLVarDeclarations.h"
29 
30 // Statements
31 #include "src/sksl/ir/SkSLBlock.h"
32 #include "src/sksl/ir/SkSLBreakStatement.h"
33 #include "src/sksl/ir/SkSLContinueStatement.h"
34 #include "src/sksl/ir/SkSLDiscardStatement.h"
35 #include "src/sksl/ir/SkSLDoStatement.h"
36 #include "src/sksl/ir/SkSLExpressionStatement.h"
37 #include "src/sksl/ir/SkSLForStatement.h"
38 #include "src/sksl/ir/SkSLIfStatement.h"
39 #include "src/sksl/ir/SkSLNop.h"
40 #include "src/sksl/ir/SkSLReturnStatement.h"
41 #include "src/sksl/ir/SkSLSwitchStatement.h"
42 
43 // Expressions
44 #include "src/sksl/ir/SkSLBinaryExpression.h"
45 #include "src/sksl/ir/SkSLChildCall.h"
46 #include "src/sksl/ir/SkSLConstructor.h"
47 #include "src/sksl/ir/SkSLConstructorDiagonalMatrix.h"
48 #include "src/sksl/ir/SkSLConstructorMatrixResize.h"
49 #include "src/sksl/ir/SkSLExternalFunctionCall.h"
50 #include "src/sksl/ir/SkSLExternalFunctionReference.h"
51 #include "src/sksl/ir/SkSLFieldAccess.h"
52 #include "src/sksl/ir/SkSLFunctionCall.h"
53 #include "src/sksl/ir/SkSLFunctionReference.h"
54 #include "src/sksl/ir/SkSLIndexExpression.h"
55 #include "src/sksl/ir/SkSLInlineMarker.h"
56 #include "src/sksl/ir/SkSLLiteral.h"
57 #include "src/sksl/ir/SkSLPostfixExpression.h"
58 #include "src/sksl/ir/SkSLPrefixExpression.h"
59 #include "src/sksl/ir/SkSLSetting.h"
60 #include "src/sksl/ir/SkSLSwizzle.h"
61 #include "src/sksl/ir/SkSLTernaryExpression.h"
62 #include "src/sksl/ir/SkSLTypeReference.h"
63 #include "src/sksl/ir/SkSLVariableReference.h"
64 
65 namespace SkSL {
66 
67 namespace {
68 
69 // Visitor that determines the merged SampleUsage for a given child in the program.
70 class MergeSampleUsageVisitor : public ProgramVisitor {
71 public:
MergeSampleUsageVisitor(const Context & context,const Variable & child,bool writesToSampleCoords)72     MergeSampleUsageVisitor(const Context& context,
73                             const Variable& child,
74                             bool writesToSampleCoords)
75             : fContext(context), fChild(child), fWritesToSampleCoords(writesToSampleCoords) {}
76 
visit(const Program & program)77     SampleUsage visit(const Program& program) {
78         fUsage = SampleUsage(); // reset to none
79         INHERITED::visit(program);
80         return fUsage;
81     }
82 
elidedSampleCoordCount() const83     int elidedSampleCoordCount() const { return fElidedSampleCoordCount; }
84 
85 protected:
86     const Context& fContext;
87     const Variable& fChild;
88     const bool fWritesToSampleCoords;
89     SampleUsage fUsage;
90     int fElidedSampleCoordCount = 0;
91 
visitExpression(const Expression & e)92     bool visitExpression(const Expression& e) override {
93         // Looking for child(...)
94         if (e.is<ChildCall>() && &e.as<ChildCall>().child() == &fChild) {
95             // Determine the type of call at this site, and merge it with the accumulated state
96             const ExpressionArray& arguments = e.as<ChildCall>().arguments();
97             SkASSERT(arguments.size() >= 1);
98 
99             const Expression* maybeCoords = arguments[0].get();
100             if (maybeCoords->type() == *fContext.fTypes.fFloat2) {
101                 // If the coords are a direct reference to the program's sample-coords, and those
102                 // coords are never modified, we can conservatively turn this into PassThrough
103                 // sampling. In all other cases, we consider it Explicit.
104                 if (!fWritesToSampleCoords && maybeCoords->is<VariableReference>() &&
105                     maybeCoords->as<VariableReference>().variable()->modifiers().fLayout.fBuiltin ==
106                             SK_MAIN_COORDS_BUILTIN) {
107                     fUsage.merge(SampleUsage::PassThrough());
108                     ++fElidedSampleCoordCount;
109                 } else {
110                     fUsage.merge(SampleUsage::Explicit());
111                 }
112             } else {
113                 // child(inputColor) or child(srcColor, dstColor) -> PassThrough
114                 fUsage.merge(SampleUsage::PassThrough());
115             }
116         }
117 
118         return INHERITED::visitExpression(e);
119     }
120 
121     using INHERITED = ProgramVisitor;
122 };
123 
124 // Visitor that searches through the program for references to a particular builtin variable
125 class BuiltinVariableVisitor : public ProgramVisitor {
126 public:
BuiltinVariableVisitor(int builtin)127     BuiltinVariableVisitor(int builtin) : fBuiltin(builtin) {}
128 
visitExpression(const Expression & e)129     bool visitExpression(const Expression& e) override {
130         if (e.is<VariableReference>()) {
131             const VariableReference& var = e.as<VariableReference>();
132             return var.variable()->modifiers().fLayout.fBuiltin == fBuiltin;
133         }
134         return INHERITED::visitExpression(e);
135     }
136 
137     int fBuiltin;
138 
139     using INHERITED = ProgramVisitor;
140 };
141 
142 // Visitor that searches for child calls from a function other than main()
143 class SampleOutsideMainVisitor : public ProgramVisitor {
144 public:
SampleOutsideMainVisitor()145     SampleOutsideMainVisitor() {}
146 
visitExpression(const Expression & e)147     bool visitExpression(const Expression& e) override {
148         if (e.is<ChildCall>()) {
149             return true;
150         }
151         return INHERITED::visitExpression(e);
152     }
153 
visitProgramElement(const ProgramElement & p)154     bool visitProgramElement(const ProgramElement& p) override {
155         return p.is<FunctionDefinition>() &&
156                !p.as<FunctionDefinition>().declaration().isMain() &&
157                INHERITED::visitProgramElement(p);
158     }
159 
160     using INHERITED = ProgramVisitor;
161 };
162 
163 // Visitor that counts the number of nodes visited
164 class NodeCountVisitor : public ProgramVisitor {
165 public:
NodeCountVisitor(int limit)166     NodeCountVisitor(int limit) : fLimit(limit) {}
167 
visit(const Statement & s)168     int visit(const Statement& s) {
169         this->visitStatement(s);
170         return fCount;
171     }
172 
visitExpression(const Expression & e)173     bool visitExpression(const Expression& e) override {
174         ++fCount;
175         return (fCount >= fLimit) || INHERITED::visitExpression(e);
176     }
177 
visitProgramElement(const ProgramElement & p)178     bool visitProgramElement(const ProgramElement& p) override {
179         ++fCount;
180         return (fCount >= fLimit) || INHERITED::visitProgramElement(p);
181     }
182 
visitStatement(const Statement & s)183     bool visitStatement(const Statement& s) override {
184         ++fCount;
185         return (fCount >= fLimit) || INHERITED::visitStatement(s);
186     }
187 
188 private:
189     int fCount = 0;
190     int fLimit;
191 
192     using INHERITED = ProgramVisitor;
193 };
194 
195 class VariableWriteVisitor : public ProgramVisitor {
196 public:
VariableWriteVisitor(const Variable * var)197     VariableWriteVisitor(const Variable* var)
198         : fVar(var) {}
199 
visit(const Statement & s)200     bool visit(const Statement& s) {
201         return this->visitStatement(s);
202     }
203 
visitExpression(const Expression & e)204     bool visitExpression(const Expression& e) override {
205         if (e.is<VariableReference>()) {
206             const VariableReference& ref = e.as<VariableReference>();
207             if (ref.variable() == fVar &&
208                 (ref.refKind() == VariableReference::RefKind::kWrite ||
209                  ref.refKind() == VariableReference::RefKind::kReadWrite ||
210                  ref.refKind() == VariableReference::RefKind::kPointer)) {
211                 return true;
212             }
213         }
214         return INHERITED::visitExpression(e);
215     }
216 
217 private:
218     const Variable* fVar;
219 
220     using INHERITED = ProgramVisitor;
221 };
222 
223 // If a caller doesn't care about errors, we can use this trivial reporter that just counts up.
224 class TrivialErrorReporter : public ErrorReporter {
225 public:
~TrivialErrorReporter()226     ~TrivialErrorReporter() override { this->reportPendingErrors({}); }
handleError(skstd::string_view,PositionInfo)227     void handleError(skstd::string_view, PositionInfo) override {}
228 };
229 
230 // This isn't actually using ProgramVisitor, because it only considers a subset of the fields for
231 // any given expression kind. For instance, when indexing an array (e.g. `x[1]`), we only want to
232 // know if the base (`x`) is assignable; the index expression (`1`) doesn't need to be.
233 class IsAssignableVisitor {
234 public:
IsAssignableVisitor(ErrorReporter * errors)235     IsAssignableVisitor(ErrorReporter* errors) : fErrors(errors) {}
236 
visit(Expression & expr,Analysis::AssignmentInfo * info)237     bool visit(Expression& expr, Analysis::AssignmentInfo* info) {
238         int oldErrorCount = fErrors->errorCount();
239         this->visitExpression(expr);
240         if (info) {
241             info->fAssignedVar = fAssignedVar;
242         }
243         return fErrors->errorCount() == oldErrorCount;
244     }
245 
visitExpression(Expression & expr)246     void visitExpression(Expression& expr) {
247         switch (expr.kind()) {
248             case Expression::Kind::kVariableReference: {
249                 VariableReference& varRef = expr.as<VariableReference>();
250                 const Variable* var = varRef.variable();
251                 if (var->modifiers().fFlags & (Modifiers::kConst_Flag | Modifiers::kUniform_Flag)) {
252                     fErrors->error(expr.fLine,
253                                    "cannot modify immutable variable '" + var->name() + "'");
254                 } else {
255                     SkASSERT(fAssignedVar == nullptr);
256                     fAssignedVar = &varRef;
257                 }
258                 break;
259             }
260             case Expression::Kind::kFieldAccess:
261                 this->visitExpression(*expr.as<FieldAccess>().base());
262                 break;
263 
264             case Expression::Kind::kSwizzle: {
265                 const Swizzle& swizzle = expr.as<Swizzle>();
266                 this->checkSwizzleWrite(swizzle);
267                 this->visitExpression(*swizzle.base());
268                 break;
269             }
270             case Expression::Kind::kIndex:
271                 this->visitExpression(*expr.as<IndexExpression>().base());
272                 break;
273 
274             case Expression::Kind::kPoison:
275                 break;
276 
277             default:
278                 fErrors->error(expr.fLine, "cannot assign to this expression");
279                 break;
280         }
281     }
282 
283 private:
checkSwizzleWrite(const Swizzle & swizzle)284     void checkSwizzleWrite(const Swizzle& swizzle) {
285         int bits = 0;
286         for (int8_t idx : swizzle.components()) {
287             SkASSERT(idx >= SwizzleComponent::X && idx <= SwizzleComponent::W);
288             int bit = 1 << idx;
289             if (bits & bit) {
290                 fErrors->error(swizzle.fLine,
291                                "cannot write to the same swizzle field more than once");
292                 break;
293             }
294             bits |= bit;
295         }
296     }
297 
298     ErrorReporter* fErrors;
299     VariableReference* fAssignedVar = nullptr;
300 
301     using INHERITED = ProgramVisitor;
302 };
303 
304 }  // namespace
305 
306 ////////////////////////////////////////////////////////////////////////////////
307 // Analysis
308 
GetSampleUsage(const Program & program,const Variable & child,bool writesToSampleCoords,int * elidedSampleCoordCount)309 SampleUsage Analysis::GetSampleUsage(const Program& program,
310                                      const Variable& child,
311                                      bool writesToSampleCoords,
312                                      int* elidedSampleCoordCount) {
313     MergeSampleUsageVisitor visitor(*program.fContext, child, writesToSampleCoords);
314     SampleUsage result = visitor.visit(program);
315     if (elidedSampleCoordCount) {
316         *elidedSampleCoordCount += visitor.elidedSampleCoordCount();
317     }
318 
319     // If AF is enabled, force to use PassThrough mode
320     if (program.fConfig != nullptr && program.fConfig->fSettings.fUseAF) {
321         result.setKind(SampleUsage::Kind::kPassThrough);
322     }
323     return result;
324 }
325 
ReferencesBuiltin(const Program & program,int builtin)326 bool Analysis::ReferencesBuiltin(const Program& program, int builtin) {
327     BuiltinVariableVisitor visitor(builtin);
328     return visitor.visit(program);
329 }
330 
ReferencesSampleCoords(const Program & program)331 bool Analysis::ReferencesSampleCoords(const Program& program) {
332     return Analysis::ReferencesBuiltin(program, SK_MAIN_COORDS_BUILTIN);
333 }
334 
ReferencesFragCoords(const Program & program)335 bool Analysis::ReferencesFragCoords(const Program& program) {
336     return Analysis::ReferencesBuiltin(program, SK_FRAGCOORD_BUILTIN);
337 }
338 
CallsSampleOutsideMain(const Program & program)339 bool Analysis::CallsSampleOutsideMain(const Program& program) {
340     SampleOutsideMainVisitor visitor;
341     return visitor.visit(program);
342 }
343 
DetectVarDeclarationWithoutScope(const Statement & stmt,ErrorReporter * errors)344 bool Analysis::DetectVarDeclarationWithoutScope(const Statement& stmt, ErrorReporter* errors) {
345     // A variable declaration can create either a lone VarDeclaration or an unscoped Block
346     // containing multiple VarDeclaration statements. We need to detect either case.
347     const Variable* var;
348     if (stmt.is<VarDeclaration>()) {
349         // The single-variable case. No blocks at all.
350         var = &stmt.as<VarDeclaration>().var();
351     } else if (stmt.is<Block>()) {
352         // The multiple-variable case: an unscoped, non-empty block...
353         const Block& block = stmt.as<Block>();
354         if (block.isScope() || block.children().empty()) {
355             return false;
356         }
357         // ... holding a variable declaration.
358         const Statement& innerStmt = *block.children().front();
359         if (!innerStmt.is<VarDeclaration>()) {
360             return false;
361         }
362         var = &innerStmt.as<VarDeclaration>().var();
363     } else {
364         // This statement wasn't a variable declaration. No problem.
365         return false;
366     }
367 
368     // Report an error.
369     SkASSERT(var);
370     if (errors) {
371         errors->error(stmt.fLine, "variable '" + var->name() + "' must be created in a scope");
372     }
373     return true;
374 }
375 
NodeCountUpToLimit(const FunctionDefinition & function,int limit)376 int Analysis::NodeCountUpToLimit(const FunctionDefinition& function, int limit) {
377     return NodeCountVisitor{limit}.visit(*function.body());
378 }
379 
StatementWritesToVariable(const Statement & stmt,const Variable & var)380 bool Analysis::StatementWritesToVariable(const Statement& stmt, const Variable& var) {
381     return VariableWriteVisitor(&var).visit(stmt);
382 }
383 
IsAssignable(Expression & expr,AssignmentInfo * info,ErrorReporter * errors)384 bool Analysis::IsAssignable(Expression& expr, AssignmentInfo* info, ErrorReporter* errors) {
385     TrivialErrorReporter trivialErrors;
386     return IsAssignableVisitor{errors ? errors : &trivialErrors}.visit(expr, info);
387 }
388 
UpdateVariableRefKind(Expression * expr,VariableReference::RefKind kind,ErrorReporter * errors)389 bool Analysis::UpdateVariableRefKind(Expression* expr,
390                                      VariableReference::RefKind kind,
391                                      ErrorReporter* errors) {
392     Analysis::AssignmentInfo info;
393     if (!Analysis::IsAssignable(*expr, &info, errors)) {
394         return false;
395     }
396     if (!info.fAssignedVar) {
397         if (errors) {
398             errors->error(expr->fLine, "can't assign to expression '" + expr->description() + "'");
399         }
400         return false;
401     }
402     info.fAssignedVar->setRefKind(kind);
403     return true;
404 }
405 
IsTrivialExpression(const Expression & expr)406 bool Analysis::IsTrivialExpression(const Expression& expr) {
407     return expr.is<Literal>() ||
408            expr.is<VariableReference>() ||
409            (expr.is<Swizzle>() &&
410             IsTrivialExpression(*expr.as<Swizzle>().base())) ||
411            (expr.is<FieldAccess>() &&
412             IsTrivialExpression(*expr.as<FieldAccess>().base())) ||
413            (expr.isAnyConstructor() &&
414             expr.asAnyConstructor().argumentSpan().size() == 1 &&
415             IsTrivialExpression(*expr.asAnyConstructor().argumentSpan().front())) ||
416            (expr.isAnyConstructor() &&
417             expr.isConstantOrUniform()) ||
418            (expr.is<IndexExpression>() &&
419             expr.as<IndexExpression>().index()->isIntLiteral() &&
420             IsTrivialExpression(*expr.as<IndexExpression>().base()));
421 }
422 
IsSameExpressionTree(const Expression & left,const Expression & right)423 bool Analysis::IsSameExpressionTree(const Expression& left, const Expression& right) {
424     if (left.kind() != right.kind() || left.type() != right.type()) {
425         return false;
426     }
427 
428     // This isn't a fully exhaustive list of expressions by any stretch of the imagination; for
429     // instance, `x[y+1] = x[y+1]` isn't detected because we don't look at BinaryExpressions.
430     // Since this is intended to be used for optimization purposes, handling the common cases is
431     // sufficient.
432     switch (left.kind()) {
433         case Expression::Kind::kLiteral:
434             return left.as<Literal>().value() == right.as<Literal>().value();
435 
436         case Expression::Kind::kConstructorArray:
437         case Expression::Kind::kConstructorArrayCast:
438         case Expression::Kind::kConstructorCompound:
439         case Expression::Kind::kConstructorCompoundCast:
440         case Expression::Kind::kConstructorDiagonalMatrix:
441         case Expression::Kind::kConstructorMatrixResize:
442         case Expression::Kind::kConstructorScalarCast:
443         case Expression::Kind::kConstructorStruct:
444         case Expression::Kind::kConstructorSplat: {
445             if (left.kind() != right.kind()) {
446                 return false;
447             }
448             const AnyConstructor& leftCtor = left.asAnyConstructor();
449             const AnyConstructor& rightCtor = right.asAnyConstructor();
450             const auto leftSpan = leftCtor.argumentSpan();
451             const auto rightSpan = rightCtor.argumentSpan();
452             if (leftSpan.size() != rightSpan.size()) {
453                 return false;
454             }
455             for (size_t index = 0; index < leftSpan.size(); ++index) {
456                 if (!IsSameExpressionTree(*leftSpan[index], *rightSpan[index])) {
457                     return false;
458                 }
459             }
460             return true;
461         }
462         case Expression::Kind::kFieldAccess:
463             return left.as<FieldAccess>().fieldIndex() == right.as<FieldAccess>().fieldIndex() &&
464                    IsSameExpressionTree(*left.as<FieldAccess>().base(),
465                                         *right.as<FieldAccess>().base());
466 
467         case Expression::Kind::kIndex:
468             return IsSameExpressionTree(*left.as<IndexExpression>().index(),
469                                         *right.as<IndexExpression>().index()) &&
470                    IsSameExpressionTree(*left.as<IndexExpression>().base(),
471                                         *right.as<IndexExpression>().base());
472 
473         case Expression::Kind::kSwizzle:
474             return left.as<Swizzle>().components() == right.as<Swizzle>().components() &&
475                    IsSameExpressionTree(*left.as<Swizzle>().base(), *right.as<Swizzle>().base());
476 
477         case Expression::Kind::kVariableReference:
478             return left.as<VariableReference>().variable() ==
479                    right.as<VariableReference>().variable();
480 
481         default:
482             return false;
483     }
484 }
485 
486 class ES2IndexingVisitor : public ProgramVisitor {
487 public:
ES2IndexingVisitor(ErrorReporter & errors)488     ES2IndexingVisitor(ErrorReporter& errors) : fErrors(errors) {}
489 
visitStatement(const Statement & s)490     bool visitStatement(const Statement& s) override {
491         if (s.is<ForStatement>()) {
492             const ForStatement& f = s.as<ForStatement>();
493             SkASSERT(f.initializer() && f.initializer()->is<VarDeclaration>());
494             const Variable* var = &f.initializer()->as<VarDeclaration>().var();
495             auto [iter, inserted] = fLoopIndices.insert(var);
496             SkASSERT(inserted);
497             bool result = this->visitStatement(*f.statement());
498             fLoopIndices.erase(iter);
499             return result;
500         }
501         return INHERITED::visitStatement(s);
502     }
503 
visitExpression(const Expression & e)504     bool visitExpression(const Expression& e) override {
505         if (e.is<IndexExpression>()) {
506             const IndexExpression& i = e.as<IndexExpression>();
507             if (!Analysis::IsConstantIndexExpression(*i.index(), &fLoopIndices)) {
508                 fErrors.error(i.fLine, "index expression must be constant");
509                 return true;
510             }
511         }
512         return INHERITED::visitExpression(e);
513     }
514 
515     using ProgramVisitor::visitProgramElement;
516 
517 private:
518     ErrorReporter& fErrors;
519     std::set<const Variable*> fLoopIndices;
520     using INHERITED = ProgramVisitor;
521 };
522 
ValidateIndexingForES2(const ProgramElement & pe,ErrorReporter & errors)523 void Analysis::ValidateIndexingForES2(const ProgramElement& pe, ErrorReporter& errors) {
524     ES2IndexingVisitor visitor(errors);
525     visitor.visitProgramElement(pe);
526 }
527 
VerifyStaticTestsAndExpressions(const Program & program)528 void Analysis::VerifyStaticTestsAndExpressions(const Program& program) {
529     class TestsAndExpressions : public ProgramVisitor {
530     public:
531         TestsAndExpressions(const Context& ctx) : fContext(ctx) {}
532 
533         bool visitProgramElement(const ProgramElement& pe) override {
534             if (pe.kind() == ProgramElement::Kind::kGlobalVar) {
535                 const VarDeclaration& decl =
536                         pe.as<GlobalVarDeclaration>().declaration()->as<VarDeclaration>();
537 
538                 size_t prevSlotsUsed = fGlobalSlotsUsed;
539                 fGlobalSlotsUsed = SkSafeMath::Add(fGlobalSlotsUsed, decl.var().type().slotCount());
540                 // To avoid overzealous error reporting, only trigger the error at the first
541                 // place where the global limit is exceeded.
542                 if (prevSlotsUsed < kVariableSlotLimit && fGlobalSlotsUsed >= kVariableSlotLimit) {
543                     fContext.fErrors->error(pe.fLine, "global variable '" + decl.var().name() +
544                                                       "' exceeds the size limit");
545                 }
546             }
547             return INHERITED::visitProgramElement(pe);
548         }
549 
550         bool visitStatement(const Statement& stmt) override {
551             if (!fContext.fConfig->fSettings.fPermitInvalidStaticTests) {
552                 switch (stmt.kind()) {
553                     case Statement::Kind::kIf:
554                         if (stmt.as<IfStatement>().isStatic()) {
555                             fContext.fErrors->error(stmt.fLine, "static if has non-static test");
556                         }
557                         break;
558 
559                     case Statement::Kind::kSwitch:
560                         if (stmt.as<SwitchStatement>().isStatic()) {
561                             fContext.fErrors->error(stmt.fLine,
562                                                     "static switch has non-static test");
563                         }
564                         break;
565 
566                     default:
567                         break;
568                 }
569             }
570             return INHERITED::visitStatement(stmt);
571         }
572 
573         bool visitExpression(const Expression& expr) override {
574             switch (expr.kind()) {
575                 case Expression::Kind::kFunctionCall: {
576                     const FunctionDeclaration& decl = expr.as<FunctionCall>().function();
577                     if (!decl.isBuiltin() && !decl.definition()) {
578                         fContext.fErrors->error(expr.fLine, "function '" + decl.description() +
579                                                             "' is not defined");
580                     }
581                     break;
582                 }
583                 case Expression::Kind::kExternalFunctionReference:
584                 case Expression::Kind::kFunctionReference:
585                 case Expression::Kind::kMethodReference:
586                 case Expression::Kind::kTypeReference:
587                     SkDEBUGFAIL("invalid reference-expr, should have been reported by coerce()");
588                     fContext.fErrors->error(expr.fLine, "invalid expression");
589                     break;
590                 default:
591                     if (expr.type() == *fContext.fTypes.fInvalid) {
592                         fContext.fErrors->error(expr.fLine, "invalid expression");
593                     }
594                     break;
595             }
596             return INHERITED::visitExpression(expr);
597         }
598 
599     private:
600         using INHERITED = ProgramVisitor;
601         size_t fGlobalSlotsUsed = 0;
602         const Context& fContext;
603     };
604 
605     // Check all of the program's owned elements. (Built-in elements are assumed to be valid.)
606     TestsAndExpressions visitor{*program.fContext};
607     for (const std::unique_ptr<ProgramElement>& element : program.fOwnedElements) {
608         visitor.visitProgramElement(*element);
609     }
610 }
611 
612 ////////////////////////////////////////////////////////////////////////////////
613 // ProgramVisitor
614 
visit(const Program & program)615 bool ProgramVisitor::visit(const Program& program) {
616     for (const ProgramElement* pe : program.elements()) {
617         if (this->visitProgramElement(*pe)) {
618             return true;
619         }
620     }
621     return false;
622 }
623 
visitExpression(typename T::Expression & e)624 template <typename T> bool TProgramVisitor<T>::visitExpression(typename T::Expression& e) {
625     switch (e.kind()) {
626         case Expression::Kind::kCodeString:
627         case Expression::Kind::kExternalFunctionReference:
628         case Expression::Kind::kFunctionReference:
629         case Expression::Kind::kLiteral:
630         case Expression::Kind::kMethodReference:
631         case Expression::Kind::kPoison:
632         case Expression::Kind::kSetting:
633         case Expression::Kind::kTypeReference:
634         case Expression::Kind::kVariableReference:
635             // Leaf expressions return false
636             return false;
637 
638         case Expression::Kind::kBinary: {
639             auto& b = e.template as<BinaryExpression>();
640             return (b.left() && this->visitExpressionPtr(b.left())) ||
641                    (b.right() && this->visitExpressionPtr(b.right()));
642         }
643         case Expression::Kind::kChildCall: {
644             // We don't visit the child variable itself, just the arguments
645             auto& c = e.template as<ChildCall>();
646             for (auto& arg : c.arguments()) {
647                 if (arg && this->visitExpressionPtr(arg)) { return true; }
648             }
649             return false;
650         }
651         case Expression::Kind::kConstructorArray:
652         case Expression::Kind::kConstructorArrayCast:
653         case Expression::Kind::kConstructorCompound:
654         case Expression::Kind::kConstructorCompoundCast:
655         case Expression::Kind::kConstructorDiagonalMatrix:
656         case Expression::Kind::kConstructorMatrixResize:
657         case Expression::Kind::kConstructorScalarCast:
658         case Expression::Kind::kConstructorSplat:
659         case Expression::Kind::kConstructorStruct: {
660             auto& c = e.asAnyConstructor();
661             for (auto& arg : c.argumentSpan()) {
662                 if (this->visitExpressionPtr(arg)) { return true; }
663             }
664             return false;
665         }
666         case Expression::Kind::kExternalFunctionCall: {
667             auto& c = e.template as<ExternalFunctionCall>();
668             for (auto& arg : c.arguments()) {
669                 if (this->visitExpressionPtr(arg)) { return true; }
670             }
671             return false;
672         }
673         case Expression::Kind::kFieldAccess:
674             return this->visitExpressionPtr(e.template as<FieldAccess>().base());
675 
676         case Expression::Kind::kFunctionCall: {
677             auto& c = e.template as<FunctionCall>();
678             for (auto& arg : c.arguments()) {
679                 if (arg && this->visitExpressionPtr(arg)) { return true; }
680             }
681             return false;
682         }
683         case Expression::Kind::kIndex: {
684             auto& i = e.template as<IndexExpression>();
685             return this->visitExpressionPtr(i.base()) || this->visitExpressionPtr(i.index());
686         }
687         case Expression::Kind::kPostfix:
688             return this->visitExpressionPtr(e.template as<PostfixExpression>().operand());
689 
690         case Expression::Kind::kPrefix:
691             return this->visitExpressionPtr(e.template as<PrefixExpression>().operand());
692 
693         case Expression::Kind::kSwizzle: {
694             auto& s = e.template as<Swizzle>();
695             return s.base() && this->visitExpressionPtr(s.base());
696         }
697 
698         case Expression::Kind::kTernary: {
699             auto& t = e.template as<TernaryExpression>();
700             return this->visitExpressionPtr(t.test()) ||
701                    (t.ifTrue() && this->visitExpressionPtr(t.ifTrue())) ||
702                    (t.ifFalse() && this->visitExpressionPtr(t.ifFalse()));
703         }
704         default:
705             SkUNREACHABLE;
706     }
707 }
708 
visitStatement(typename T::Statement & s)709 template <typename T> bool TProgramVisitor<T>::visitStatement(typename T::Statement& s) {
710     switch (s.kind()) {
711         case Statement::Kind::kBreak:
712         case Statement::Kind::kContinue:
713         case Statement::Kind::kDiscard:
714         case Statement::Kind::kInlineMarker:
715         case Statement::Kind::kNop:
716             // Leaf statements just return false
717             return false;
718 
719         case Statement::Kind::kBlock:
720             for (auto& stmt : s.template as<Block>().children()) {
721                 if (stmt && this->visitStatementPtr(stmt)) {
722                     return true;
723                 }
724             }
725             return false;
726 
727         case Statement::Kind::kSwitchCase: {
728             auto& sc = s.template as<SwitchCase>();
729             if (sc.value() && this->visitExpressionPtr(sc.value())) {
730                 return true;
731             }
732             return this->visitStatementPtr(sc.statement());
733         }
734         case Statement::Kind::kDo: {
735             auto& d = s.template as<DoStatement>();
736             return this->visitExpressionPtr(d.test()) || this->visitStatementPtr(d.statement());
737         }
738         case Statement::Kind::kExpression:
739             return this->visitExpressionPtr(s.template as<ExpressionStatement>().expression());
740 
741         case Statement::Kind::kFor: {
742             auto& f = s.template as<ForStatement>();
743             return (f.initializer() && this->visitStatementPtr(f.initializer())) ||
744                    (f.test() && this->visitExpressionPtr(f.test())) ||
745                    (f.next() && this->visitExpressionPtr(f.next())) ||
746                    this->visitStatementPtr(f.statement());
747         }
748         case Statement::Kind::kIf: {
749             auto& i = s.template as<IfStatement>();
750             return (i.test() && this->visitExpressionPtr(i.test())) ||
751                    (i.ifTrue() && this->visitStatementPtr(i.ifTrue())) ||
752                    (i.ifFalse() && this->visitStatementPtr(i.ifFalse()));
753         }
754         case Statement::Kind::kReturn: {
755             auto& r = s.template as<ReturnStatement>();
756             return r.expression() && this->visitExpressionPtr(r.expression());
757         }
758         case Statement::Kind::kSwitch: {
759             auto& sw = s.template as<SwitchStatement>();
760             if (this->visitExpressionPtr(sw.value())) {
761                 return true;
762             }
763             for (auto& c : sw.cases()) {
764                 if (this->visitStatementPtr(c)) {
765                     return true;
766                 }
767             }
768             return false;
769         }
770         case Statement::Kind::kVarDeclaration: {
771             auto& v = s.template as<VarDeclaration>();
772             return v.value() && this->visitExpressionPtr(v.value());
773         }
774         default:
775             SkUNREACHABLE;
776     }
777 }
778 
visitProgramElement(typename T::ProgramElement & pe)779 template <typename T> bool TProgramVisitor<T>::visitProgramElement(typename T::ProgramElement& pe) {
780     switch (pe.kind()) {
781         case ProgramElement::Kind::kExtension:
782         case ProgramElement::Kind::kFunctionPrototype:
783         case ProgramElement::Kind::kInterfaceBlock:
784         case ProgramElement::Kind::kModifiers:
785         case ProgramElement::Kind::kStructDefinition:
786             // Leaf program elements just return false by default
787             return false;
788 
789         case ProgramElement::Kind::kFunction:
790             return this->visitStatementPtr(pe.template as<FunctionDefinition>().body());
791 
792         case ProgramElement::Kind::kGlobalVar:
793             return this->visitStatementPtr(pe.template as<GlobalVarDeclaration>().declaration());
794 
795         default:
796             SkUNREACHABLE;
797     }
798 }
799 
800 template class TProgramVisitor<ProgramVisitorTypes>;
801 template class TProgramVisitor<ProgramWriterTypes>;
802 
803 }  // namespace SkSL
804