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