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