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