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