• 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/core/SkSpan.h"
11 #include "include/core/SkTypes.h"
12 #include "include/private/SkSLDefines.h"
13 #include "include/private/SkSLIRNode.h"
14 #include "include/private/SkSLLayout.h"
15 #include "include/private/SkSLModifiers.h"
16 #include "include/private/SkSLProgramElement.h"
17 #include "include/private/SkSLSampleUsage.h"
18 #include "include/private/SkSLStatement.h"
19 #include "include/private/base/SkTArray.h"
20 #include "include/sksl/SkSLErrorReporter.h"
21 #include "include/sksl/SkSLOperator.h"
22 #include "src/core/SkTHash.h"
23 #include "src/sksl/SkSLBuiltinTypes.h"
24 #include "src/sksl/SkSLCompiler.h"
25 #include "src/sksl/SkSLConstantFolder.h"
26 #include "src/sksl/SkSLContext.h"
27 #include "src/sksl/SkSLIntrinsicList.h"
28 #include "src/sksl/analysis/SkSLNoOpErrorReporter.h"
29 #include "src/sksl/analysis/SkSLProgramUsage.h"
30 #include "src/sksl/analysis/SkSLProgramVisitor.h"
31 #include "src/sksl/ir/SkSLBinaryExpression.h"
32 #include "src/sksl/ir/SkSLBlock.h"
33 #include "src/sksl/ir/SkSLChildCall.h"
34 #include "src/sksl/ir/SkSLConstructor.h"
35 #include "src/sksl/ir/SkSLDoStatement.h"
36 #include "src/sksl/ir/SkSLExpression.h"
37 #include "src/sksl/ir/SkSLExpressionStatement.h"
38 #include "src/sksl/ir/SkSLFieldAccess.h"
39 #include "src/sksl/ir/SkSLForStatement.h"
40 #include "src/sksl/ir/SkSLFunctionCall.h"
41 #include "src/sksl/ir/SkSLFunctionDeclaration.h"
42 #include "src/sksl/ir/SkSLFunctionDefinition.h"
43 #include "src/sksl/ir/SkSLIfStatement.h"
44 #include "src/sksl/ir/SkSLIndexExpression.h"
45 #include "src/sksl/ir/SkSLPostfixExpression.h"
46 #include "src/sksl/ir/SkSLPrefixExpression.h"
47 #include "src/sksl/ir/SkSLProgram.h"
48 #include "src/sksl/ir/SkSLReturnStatement.h"
49 #include "src/sksl/ir/SkSLSwitchCase.h"
50 #include "src/sksl/ir/SkSLSwitchStatement.h"
51 #include "src/sksl/ir/SkSLSwizzle.h"
52 #include "src/sksl/ir/SkSLTernaryExpression.h"
53 #include "src/sksl/ir/SkSLType.h"
54 #include "src/sksl/ir/SkSLVarDeclarations.h"
55 #include "src/sksl/ir/SkSLVariable.h"
56 #include "src/sksl/ir/SkSLVariableReference.h"
57 #include "src/sksl/transform/SkSLProgramWriter.h"
58 
59 #include <optional>
60 #include <string>
61 #include <string_view>
62 
63 namespace SkSL {
64 
65 namespace {
66 
67 // Visitor that determines the merged SampleUsage for a given child in the program.
68 class MergeSampleUsageVisitor : public ProgramVisitor {
69 public:
MergeSampleUsageVisitor(const Context & context,const Variable & child,bool writesToSampleCoords)70     MergeSampleUsageVisitor(const Context& context,
71                             const Variable& child,
72                             bool writesToSampleCoords)
73             : fContext(context), fChild(child), fWritesToSampleCoords(writesToSampleCoords) {}
74 
visit(const Program & program)75     SampleUsage visit(const Program& program) {
76         fUsage = SampleUsage(); // reset to none
77         INHERITED::visit(program);
78         return fUsage;
79     }
80 
elidedSampleCoordCount() const81     int elidedSampleCoordCount() const { return fElidedSampleCoordCount; }
82 
83 protected:
84     const Context& fContext;
85     const Variable& fChild;
86     const bool fWritesToSampleCoords;
87     SampleUsage fUsage;
88     int fElidedSampleCoordCount = 0;
89 
visitExpression(const Expression & e)90     bool visitExpression(const Expression& e) override {
91         // Looking for child(...)
92         if (e.is<ChildCall>() && &e.as<ChildCall>().child() == &fChild) {
93             // Determine the type of call at this site, and merge it with the accumulated state
94             const ExpressionArray& arguments = e.as<ChildCall>().arguments();
95             SkASSERT(arguments.size() >= 1);
96 
97             const Expression* maybeCoords = arguments[0].get();
98             if (maybeCoords->type().matches(*fContext.fTypes.fFloat2)) {
99                 // If the coords are a direct reference to the program's sample-coords, and those
100                 // coords are never modified, we can conservatively turn this into PassThrough
101                 // sampling. In all other cases, we consider it Explicit.
102                 if (!fWritesToSampleCoords && maybeCoords->is<VariableReference>() &&
103                     maybeCoords->as<VariableReference>().variable()->modifiers().fLayout.fBuiltin ==
104                             SK_MAIN_COORDS_BUILTIN) {
105                     fUsage.merge(SampleUsage::PassThrough());
106                     ++fElidedSampleCoordCount;
107                 } else {
108                     fUsage.merge(SampleUsage::Explicit());
109                 }
110             } else {
111                 // child(inputColor) or child(srcColor, dstColor) -> PassThrough
112                 fUsage.merge(SampleUsage::PassThrough());
113             }
114         }
115 
116         return INHERITED::visitExpression(e);
117     }
118 
119     using INHERITED = ProgramVisitor;
120 };
121 
122 // Visitor that searches for child calls from a function other than main()
123 class SampleOutsideMainVisitor : public ProgramVisitor {
124 public:
SampleOutsideMainVisitor()125     SampleOutsideMainVisitor() {}
126 
visitExpression(const Expression & e)127     bool visitExpression(const Expression& e) override {
128         if (e.is<ChildCall>()) {
129             return true;
130         }
131         return INHERITED::visitExpression(e);
132     }
133 
visitProgramElement(const ProgramElement & p)134     bool visitProgramElement(const ProgramElement& p) override {
135         return p.is<FunctionDefinition>() &&
136                !p.as<FunctionDefinition>().declaration().isMain() &&
137                INHERITED::visitProgramElement(p);
138     }
139 
140     using INHERITED = ProgramVisitor;
141 };
142 
143 class ReturnsNonOpaqueColorVisitor : public ProgramVisitor {
144 public:
ReturnsNonOpaqueColorVisitor()145     ReturnsNonOpaqueColorVisitor() {}
146 
visitStatement(const Statement & s)147     bool visitStatement(const Statement& s) override {
148         if (s.is<ReturnStatement>()) {
149             const Expression* e = s.as<ReturnStatement>().expression().get();
150             bool knownOpaque = e && e->type().slotCount() == 4 &&
151                                ConstantFolder::GetConstantValueForVariable(*e)
152                                                ->getConstantValue(/*n=*/3)
153                                                .value_or(0) == 1;
154             return !knownOpaque;
155         }
156         return INHERITED::visitStatement(s);
157     }
158 
visitExpression(const Expression & e)159     bool visitExpression(const Expression& e) override {
160         // No need to recurse into expressions, these can never contain return statements
161         return false;
162     }
163 
164     using INHERITED = ProgramVisitor;
165     using INHERITED::visitProgramElement;
166 };
167 
168 // Visitor that counts the number of nodes visited
169 class NodeCountVisitor : public ProgramVisitor {
170 public:
NodeCountVisitor(int limit)171     NodeCountVisitor(int limit) : fLimit(limit) {}
172 
visit(const Statement & s)173     int visit(const Statement& s) {
174         this->visitStatement(s);
175         return fCount;
176     }
177 
visitExpression(const Expression & e)178     bool visitExpression(const Expression& e) override {
179         ++fCount;
180         return (fCount >= fLimit) || INHERITED::visitExpression(e);
181     }
182 
visitProgramElement(const ProgramElement & p)183     bool visitProgramElement(const ProgramElement& p) override {
184         ++fCount;
185         return (fCount >= fLimit) || INHERITED::visitProgramElement(p);
186     }
187 
visitStatement(const Statement & s)188     bool visitStatement(const Statement& s) override {
189         ++fCount;
190         return (fCount >= fLimit) || INHERITED::visitStatement(s);
191     }
192 
193 private:
194     int fCount = 0;
195     int fLimit;
196 
197     using INHERITED = ProgramVisitor;
198 };
199 
200 class VariableWriteVisitor : public ProgramVisitor {
201 public:
VariableWriteVisitor(const Variable * var)202     VariableWriteVisitor(const Variable* var)
203         : fVar(var) {}
204 
visit(const Statement & s)205     bool visit(const Statement& s) {
206         return this->visitStatement(s);
207     }
208 
visitExpression(const Expression & e)209     bool visitExpression(const Expression& e) override {
210         if (e.is<VariableReference>()) {
211             const VariableReference& ref = e.as<VariableReference>();
212             if (ref.variable() == fVar &&
213                 (ref.refKind() == VariableReference::RefKind::kWrite ||
214                  ref.refKind() == VariableReference::RefKind::kReadWrite ||
215                  ref.refKind() == VariableReference::RefKind::kPointer)) {
216                 return true;
217             }
218         }
219         return INHERITED::visitExpression(e);
220     }
221 
222 private:
223     const Variable* fVar;
224 
225     using INHERITED = ProgramVisitor;
226 };
227 
228 // This isn't actually using ProgramVisitor, because it only considers a subset of the fields for
229 // any given expression kind. For instance, when indexing an array (e.g. `x[1]`), we only want to
230 // know if the base (`x`) is assignable; the index expression (`1`) doesn't need to be.
231 class IsAssignableVisitor {
232 public:
IsAssignableVisitor(ErrorReporter * errors)233     IsAssignableVisitor(ErrorReporter* errors) : fErrors(errors) {}
234 
visit(Expression & expr,Analysis::AssignmentInfo * info)235     bool visit(Expression& expr, Analysis::AssignmentInfo* info) {
236         int oldErrorCount = fErrors->errorCount();
237         this->visitExpression(expr);
238         if (info) {
239             info->fAssignedVar = fAssignedVar;
240         }
241         return fErrors->errorCount() == oldErrorCount;
242     }
243 
visitExpression(Expression & expr,const FieldAccess * fieldAccess=nullptr)244     void visitExpression(Expression& expr, const FieldAccess* fieldAccess = nullptr) {
245         switch (expr.kind()) {
246             case Expression::Kind::kVariableReference: {
247                 VariableReference& varRef = expr.as<VariableReference>();
248                 const Variable* var = varRef.variable();
249                 auto fieldName = [&] {
250                     return fieldAccess ? fieldAccess->description(OperatorPrecedence::kTopLevel)
251                                        : std::string(var->name());
252                 };
253                 if (var->modifiers().fFlags & (Modifiers::kConst_Flag | Modifiers::kUniform_Flag)) {
254                     fErrors->error(expr.fPosition,
255                                    "cannot modify immutable variable '" + fieldName() + "'");
256                 } else if (var->storage() == Variable::Storage::kGlobal &&
257                            (var->modifiers().fFlags & Modifiers::kIn_Flag)) {
258                     fErrors->error(expr.fPosition,
259                                    "cannot modify pipeline input variable '" + fieldName() + "'");
260                 } else {
261                     SkASSERT(fAssignedVar == nullptr);
262                     fAssignedVar = &varRef;
263                 }
264                 break;
265             }
266             case Expression::Kind::kFieldAccess: {
267                 const FieldAccess& f = expr.as<FieldAccess>();
268                 this->visitExpression(*f.base(), &f);
269                 break;
270             }
271             case Expression::Kind::kSwizzle: {
272                 const Swizzle& swizzle = expr.as<Swizzle>();
273                 this->checkSwizzleWrite(swizzle);
274                 this->visitExpression(*swizzle.base(), fieldAccess);
275                 break;
276             }
277             case Expression::Kind::kIndex:
278                 this->visitExpression(*expr.as<IndexExpression>().base(), fieldAccess);
279                 break;
280 
281             case Expression::Kind::kPoison:
282                 break;
283 
284             default:
285                 fErrors->error(expr.fPosition, "cannot assign to this expression");
286                 break;
287         }
288     }
289 
290 private:
checkSwizzleWrite(const Swizzle & swizzle)291     void checkSwizzleWrite(const Swizzle& swizzle) {
292         int bits = 0;
293         for (int8_t idx : swizzle.components()) {
294             SkASSERT(idx >= SwizzleComponent::X && idx <= SwizzleComponent::W);
295             int bit = 1 << idx;
296             if (bits & bit) {
297                 fErrors->error(swizzle.fPosition,
298                                "cannot write to the same swizzle field more than once");
299                 break;
300             }
301             bits |= bit;
302         }
303     }
304 
305     ErrorReporter* fErrors;
306     VariableReference* fAssignedVar = nullptr;
307 
308     using INHERITED = ProgramVisitor;
309 };
310 
311 }  // namespace
312 
313 ////////////////////////////////////////////////////////////////////////////////
314 // Analysis
315 
GetSampleUsage(const Program & program,const Variable & child,bool writesToSampleCoords,int * elidedSampleCoordCount)316 SampleUsage Analysis::GetSampleUsage(const Program& program,
317                                      const Variable& child,
318                                      bool writesToSampleCoords,
319                                      int* elidedSampleCoordCount) {
320     MergeSampleUsageVisitor visitor(*program.fContext, child, writesToSampleCoords);
321     SampleUsage result = visitor.visit(program);
322     if (elidedSampleCoordCount) {
323         *elidedSampleCoordCount += visitor.elidedSampleCoordCount();
324     }
325     return result;
326 }
327 
ReferencesBuiltin(const Program & program,int builtin)328 bool Analysis::ReferencesBuiltin(const Program& program, int builtin) {
329     SkASSERT(program.fUsage);
330     for (const auto& [variable, counts] : program.fUsage->fVariableCounts) {
331         if (counts.fRead > 0 && variable->modifiers().fLayout.fBuiltin == builtin) {
332             return true;
333         }
334     }
335     return false;
336 }
337 
ReferencesSampleCoords(const Program & program)338 bool Analysis::ReferencesSampleCoords(const Program& program) {
339     return Analysis::ReferencesBuiltin(program, SK_MAIN_COORDS_BUILTIN);
340 }
341 
ReferencesFragCoords(const Program & program)342 bool Analysis::ReferencesFragCoords(const Program& program) {
343     return Analysis::ReferencesBuiltin(program, SK_FRAGCOORD_BUILTIN);
344 }
345 
CallsSampleOutsideMain(const Program & program)346 bool Analysis::CallsSampleOutsideMain(const Program& program) {
347     SampleOutsideMainVisitor visitor;
348     return visitor.visit(program);
349 }
350 
CallsColorTransformIntrinsics(const Program & program)351 bool Analysis::CallsColorTransformIntrinsics(const Program& program) {
352     for (auto [fn, count] : program.usage()->fCallCounts) {
353         if (count != 0 && (fn->intrinsicKind() == k_toLinearSrgb_IntrinsicKind ||
354                            fn->intrinsicKind() == k_fromLinearSrgb_IntrinsicKind)) {
355             return true;
356         }
357     }
358     return false;
359 }
360 
ReturnsOpaqueColor(const FunctionDefinition & function)361 bool Analysis::ReturnsOpaqueColor(const FunctionDefinition& function) {
362     ReturnsNonOpaqueColorVisitor visitor;
363     return !visitor.visitProgramElement(function);
364 }
365 
ContainsRTAdjust(const Expression & expr)366 bool Analysis::ContainsRTAdjust(const Expression& expr) {
367     class ContainsRTAdjustVisitor : public ProgramVisitor {
368     public:
369         bool visitExpression(const Expression& expr) override {
370             if (expr.is<VariableReference>() &&
371                 expr.as<VariableReference>().variable()->name() == Compiler::RTADJUST_NAME) {
372                 return true;
373             }
374             return INHERITED::visitExpression(expr);
375         }
376 
377         using INHERITED = ProgramVisitor;
378     };
379 
380     ContainsRTAdjustVisitor visitor;
381     return visitor.visitExpression(expr);
382 }
383 
IsCompileTimeConstant(const Expression & expr)384 bool Analysis::IsCompileTimeConstant(const Expression& expr) {
385     class IsCompileTimeConstantVisitor : public ProgramVisitor {
386     public:
387         bool visitExpression(const Expression& expr) override {
388             switch (expr.kind()) {
389                 case Expression::Kind::kLiteral:
390                     // Literals are compile-time constants.
391                     return false;
392 
393                 case Expression::Kind::kConstructorArray:
394                 case Expression::Kind::kConstructorCompound:
395                 case Expression::Kind::kConstructorDiagonalMatrix:
396                 case Expression::Kind::kConstructorMatrixResize:
397                 case Expression::Kind::kConstructorSplat:
398                 case Expression::Kind::kConstructorStruct:
399                     // Constructors might be compile-time constants, if they are composed entirely
400                     // of literals and constructors. (Casting constructors are intentionally omitted
401                     // here. If the value inside was a compile-time constant, we would have not have
402                     // generated a cast at all.)
403                     return INHERITED::visitExpression(expr);
404 
405                 default:
406                     // This expression isn't a compile-time constant.
407                     fIsConstant = false;
408                     return true;
409             }
410         }
411 
412         bool fIsConstant = true;
413         using INHERITED = ProgramVisitor;
414     };
415 
416     IsCompileTimeConstantVisitor visitor;
417     visitor.visitExpression(expr);
418     return visitor.fIsConstant;
419 }
420 
DetectVarDeclarationWithoutScope(const Statement & stmt,ErrorReporter * errors)421 bool Analysis::DetectVarDeclarationWithoutScope(const Statement& stmt, ErrorReporter* errors) {
422     // A variable declaration can create either a lone VarDeclaration or an unscoped Block
423     // containing multiple VarDeclaration statements. We need to detect either case.
424     const Variable* var;
425     if (stmt.is<VarDeclaration>()) {
426         // The single-variable case. No blocks at all.
427         var = stmt.as<VarDeclaration>().var();
428     } else if (stmt.is<Block>()) {
429         // The multiple-variable case: an unscoped, non-empty block...
430         const Block& block = stmt.as<Block>();
431         if (block.isScope() || block.children().empty()) {
432             return false;
433         }
434         // ... holding a variable declaration.
435         const Statement& innerStmt = *block.children().front();
436         if (!innerStmt.is<VarDeclaration>()) {
437             return false;
438         }
439         var = innerStmt.as<VarDeclaration>().var();
440     } else {
441         // This statement wasn't a variable declaration. No problem.
442         return false;
443     }
444 
445     // Report an error.
446     SkASSERT(var);
447     if (errors) {
448         errors->error(var->fPosition,
449                       "variable '" + std::string(var->name()) + "' must be created in a scope");
450     }
451     return true;
452 }
453 
NodeCountUpToLimit(const FunctionDefinition & function,int limit)454 int Analysis::NodeCountUpToLimit(const FunctionDefinition& function, int limit) {
455     return NodeCountVisitor{limit}.visit(*function.body());
456 }
457 
StatementWritesToVariable(const Statement & stmt,const Variable & var)458 bool Analysis::StatementWritesToVariable(const Statement& stmt, const Variable& var) {
459     return VariableWriteVisitor(&var).visit(stmt);
460 }
461 
IsAssignable(Expression & expr,AssignmentInfo * info,ErrorReporter * errors)462 bool Analysis::IsAssignable(Expression& expr, AssignmentInfo* info, ErrorReporter* errors) {
463     NoOpErrorReporter unusedErrors;
464     return IsAssignableVisitor{errors ? errors : &unusedErrors}.visit(expr, info);
465 }
466 
UpdateVariableRefKind(Expression * expr,VariableReference::RefKind kind,ErrorReporter * errors)467 bool Analysis::UpdateVariableRefKind(Expression* expr,
468                                      VariableReference::RefKind kind,
469                                      ErrorReporter* errors) {
470     Analysis::AssignmentInfo info;
471     if (!Analysis::IsAssignable(*expr, &info, errors)) {
472         return false;
473     }
474     if (!info.fAssignedVar) {
475         if (errors) {
476             errors->error(expr->fPosition, "can't assign to expression '" + expr->description() +
477                     "'");
478         }
479         return false;
480     }
481     info.fAssignedVar->setRefKind(kind);
482     return true;
483 }
484 
485 class ES2IndexingVisitor : public ProgramVisitor {
486 public:
ES2IndexingVisitor(ErrorReporter & errors)487     ES2IndexingVisitor(ErrorReporter& errors) : fErrors(errors) {}
488 
visitStatement(const Statement & s)489     bool visitStatement(const Statement& s) override {
490         if (s.is<ForStatement>()) {
491             const ForStatement& f = s.as<ForStatement>();
492             SkASSERT(f.initializer() && f.initializer()->is<VarDeclaration>());
493             const Variable* var = f.initializer()->as<VarDeclaration>().var();
494             auto [iter, inserted] = fLoopIndices.insert(var);
495             SkASSERT(inserted);
496             bool result = this->visitStatement(*f.statement());
497             fLoopIndices.erase(iter);
498             return result;
499         }
500         return INHERITED::visitStatement(s);
501     }
502 
visitExpression(const Expression & e)503     bool visitExpression(const Expression& e) override {
504         if (e.is<IndexExpression>()) {
505             const IndexExpression& i = e.as<IndexExpression>();
506             if (!Analysis::IsConstantIndexExpression(*i.index(), &fLoopIndices)) {
507                 fErrors.error(i.fPosition, "index expression must be constant");
508                 return true;
509             }
510         }
511         return INHERITED::visitExpression(e);
512     }
513 
514     using ProgramVisitor::visitProgramElement;
515 
516 private:
517     ErrorReporter& fErrors;
518     std::set<const Variable*> fLoopIndices;
519     using INHERITED = ProgramVisitor;
520 };
521 
ValidateIndexingForES2(const ProgramElement & pe,ErrorReporter & errors)522 void Analysis::ValidateIndexingForES2(const ProgramElement& pe, ErrorReporter& errors) {
523     ES2IndexingVisitor visitor(errors);
524     visitor.visitProgramElement(pe);
525 }
526 
527 ////////////////////////////////////////////////////////////////////////////////
528 // ProgramVisitor
529 
visit(const Program & program)530 bool ProgramVisitor::visit(const Program& program) {
531     for (const ProgramElement* pe : program.elements()) {
532         if (this->visitProgramElement(*pe)) {
533             return true;
534         }
535     }
536     return false;
537 }
538 
visitExpression(typename T::Expression & e)539 template <typename T> bool TProgramVisitor<T>::visitExpression(typename T::Expression& e) {
540     switch (e.kind()) {
541         case Expression::Kind::kFunctionReference:
542         case Expression::Kind::kLiteral:
543         case Expression::Kind::kMethodReference:
544         case Expression::Kind::kPoison:
545         case Expression::Kind::kSetting:
546         case Expression::Kind::kTypeReference:
547         case Expression::Kind::kVariableReference:
548             // Leaf expressions return false
549             return false;
550 
551         case Expression::Kind::kBinary: {
552             auto& b = e.template as<BinaryExpression>();
553             return (b.left() && this->visitExpressionPtr(b.left())) ||
554                    (b.right() && this->visitExpressionPtr(b.right()));
555         }
556         case Expression::Kind::kChildCall: {
557             // We don't visit the child variable itself, just the arguments
558             auto& c = e.template as<ChildCall>();
559             for (auto& arg : c.arguments()) {
560                 if (arg && this->visitExpressionPtr(arg)) { return true; }
561             }
562             return false;
563         }
564         case Expression::Kind::kConstructorArray:
565         case Expression::Kind::kConstructorArrayCast:
566         case Expression::Kind::kConstructorCompound:
567         case Expression::Kind::kConstructorCompoundCast:
568         case Expression::Kind::kConstructorDiagonalMatrix:
569         case Expression::Kind::kConstructorMatrixResize:
570         case Expression::Kind::kConstructorScalarCast:
571         case Expression::Kind::kConstructorSplat:
572         case Expression::Kind::kConstructorStruct: {
573             auto& c = e.asAnyConstructor();
574             for (auto& arg : c.argumentSpan()) {
575                 if (this->visitExpressionPtr(arg)) { return true; }
576             }
577             return false;
578         }
579         case Expression::Kind::kFieldAccess:
580             return this->visitExpressionPtr(e.template as<FieldAccess>().base());
581 
582         case Expression::Kind::kFunctionCall: {
583             auto& c = e.template as<FunctionCall>();
584             for (auto& arg : c.arguments()) {
585                 if (arg && this->visitExpressionPtr(arg)) { return true; }
586             }
587             return false;
588         }
589         case Expression::Kind::kIndex: {
590             auto& i = e.template as<IndexExpression>();
591             return this->visitExpressionPtr(i.base()) || this->visitExpressionPtr(i.index());
592         }
593         case Expression::Kind::kPostfix:
594             return this->visitExpressionPtr(e.template as<PostfixExpression>().operand());
595 
596         case Expression::Kind::kPrefix:
597             return this->visitExpressionPtr(e.template as<PrefixExpression>().operand());
598 
599         case Expression::Kind::kSwizzle: {
600             auto& s = e.template as<Swizzle>();
601             return s.base() && this->visitExpressionPtr(s.base());
602         }
603 
604         case Expression::Kind::kTernary: {
605             auto& t = e.template as<TernaryExpression>();
606             return this->visitExpressionPtr(t.test()) ||
607                    (t.ifTrue() && this->visitExpressionPtr(t.ifTrue())) ||
608                    (t.ifFalse() && this->visitExpressionPtr(t.ifFalse()));
609         }
610         default:
611             SkUNREACHABLE;
612     }
613 }
614 
visitStatement(typename T::Statement & s)615 template <typename T> bool TProgramVisitor<T>::visitStatement(typename T::Statement& s) {
616     switch (s.kind()) {
617         case Statement::Kind::kBreak:
618         case Statement::Kind::kContinue:
619         case Statement::Kind::kDiscard:
620         case Statement::Kind::kNop:
621             // Leaf statements just return false
622             return false;
623 
624         case Statement::Kind::kBlock:
625             for (auto& stmt : s.template as<Block>().children()) {
626                 if (stmt && this->visitStatementPtr(stmt)) {
627                     return true;
628                 }
629             }
630             return false;
631 
632         case Statement::Kind::kSwitchCase: {
633             auto& sc = s.template as<SwitchCase>();
634             return this->visitStatementPtr(sc.statement());
635         }
636         case Statement::Kind::kDo: {
637             auto& d = s.template as<DoStatement>();
638             return this->visitExpressionPtr(d.test()) || this->visitStatementPtr(d.statement());
639         }
640         case Statement::Kind::kExpression:
641             return this->visitExpressionPtr(s.template as<ExpressionStatement>().expression());
642 
643         case Statement::Kind::kFor: {
644             auto& f = s.template as<ForStatement>();
645             return (f.initializer() && this->visitStatementPtr(f.initializer())) ||
646                    (f.test() && this->visitExpressionPtr(f.test())) ||
647                    (f.next() && this->visitExpressionPtr(f.next())) ||
648                    this->visitStatementPtr(f.statement());
649         }
650         case Statement::Kind::kIf: {
651             auto& i = s.template as<IfStatement>();
652             return (i.test() && this->visitExpressionPtr(i.test())) ||
653                    (i.ifTrue() && this->visitStatementPtr(i.ifTrue())) ||
654                    (i.ifFalse() && this->visitStatementPtr(i.ifFalse()));
655         }
656         case Statement::Kind::kReturn: {
657             auto& r = s.template as<ReturnStatement>();
658             return r.expression() && this->visitExpressionPtr(r.expression());
659         }
660         case Statement::Kind::kSwitch: {
661             auto& sw = s.template as<SwitchStatement>();
662             if (this->visitExpressionPtr(sw.value())) {
663                 return true;
664             }
665             for (auto& c : sw.cases()) {
666                 if (this->visitStatementPtr(c)) {
667                     return true;
668                 }
669             }
670             return false;
671         }
672         case Statement::Kind::kVarDeclaration: {
673             auto& v = s.template as<VarDeclaration>();
674             return v.value() && this->visitExpressionPtr(v.value());
675         }
676         default:
677             SkUNREACHABLE;
678     }
679 }
680 
visitProgramElement(typename T::ProgramElement & pe)681 template <typename T> bool TProgramVisitor<T>::visitProgramElement(typename T::ProgramElement& pe) {
682     switch (pe.kind()) {
683         case ProgramElement::Kind::kExtension:
684         case ProgramElement::Kind::kFunctionPrototype:
685         case ProgramElement::Kind::kInterfaceBlock:
686         case ProgramElement::Kind::kModifiers:
687         case ProgramElement::Kind::kStructDefinition:
688             // Leaf program elements just return false by default
689             return false;
690 
691         case ProgramElement::Kind::kFunction:
692             return this->visitStatementPtr(pe.template as<FunctionDefinition>().body());
693 
694         case ProgramElement::Kind::kGlobalVar:
695             return this->visitStatementPtr(pe.template as<GlobalVarDeclaration>().declaration());
696 
697         default:
698             SkUNREACHABLE;
699     }
700 }
701 
702 template class TProgramVisitor<ProgramVisitorTypes>;
703 template class TProgramVisitor<ProgramWriterTypes>;
704 
705 }  // namespace SkSL
706