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/private/SkSLModifiers.h"
11 #include "include/private/SkSLProgramElement.h"
12 #include "include/private/SkSLSampleUsage.h"
13 #include "include/private/SkSLStatement.h"
14 #include "src/sksl/SkSLCompiler.h"
15 #include "src/sksl/SkSLErrorReporter.h"
16 #include "src/sksl/ir/SkSLExpression.h"
17 #include "src/sksl/ir/SkSLProgram.h"
18
19 // ProgramElements
20 #include "src/sksl/ir/SkSLEnum.h"
21 #include "src/sksl/ir/SkSLExtension.h"
22 #include "src/sksl/ir/SkSLFunctionDefinition.h"
23 #include "src/sksl/ir/SkSLInterfaceBlock.h"
24 #include "src/sksl/ir/SkSLSection.h"
25 #include "src/sksl/ir/SkSLVarDeclarations.h"
26
27 // Statements
28 #include "src/sksl/ir/SkSLBlock.h"
29 #include "src/sksl/ir/SkSLBreakStatement.h"
30 #include "src/sksl/ir/SkSLContinueStatement.h"
31 #include "src/sksl/ir/SkSLDiscardStatement.h"
32 #include "src/sksl/ir/SkSLDoStatement.h"
33 #include "src/sksl/ir/SkSLExpressionStatement.h"
34 #include "src/sksl/ir/SkSLForStatement.h"
35 #include "src/sksl/ir/SkSLIfStatement.h"
36 #include "src/sksl/ir/SkSLNop.h"
37 #include "src/sksl/ir/SkSLReturnStatement.h"
38 #include "src/sksl/ir/SkSLSwitchStatement.h"
39
40 // Expressions
41 #include "src/sksl/ir/SkSLBinaryExpression.h"
42 #include "src/sksl/ir/SkSLBoolLiteral.h"
43 #include "src/sksl/ir/SkSLConstructor.h"
44 #include "src/sksl/ir/SkSLConstructorDiagonalMatrix.h"
45 #include "src/sksl/ir/SkSLConstructorMatrixResize.h"
46 #include "src/sksl/ir/SkSLExternalFunctionCall.h"
47 #include "src/sksl/ir/SkSLExternalFunctionReference.h"
48 #include "src/sksl/ir/SkSLFieldAccess.h"
49 #include "src/sksl/ir/SkSLFloatLiteral.h"
50 #include "src/sksl/ir/SkSLFunctionCall.h"
51 #include "src/sksl/ir/SkSLFunctionReference.h"
52 #include "src/sksl/ir/SkSLIndexExpression.h"
53 #include "src/sksl/ir/SkSLInlineMarker.h"
54 #include "src/sksl/ir/SkSLIntLiteral.h"
55 #include "src/sksl/ir/SkSLPostfixExpression.h"
56 #include "src/sksl/ir/SkSLPrefixExpression.h"
57 #include "src/sksl/ir/SkSLSetting.h"
58 #include "src/sksl/ir/SkSLSwizzle.h"
59 #include "src/sksl/ir/SkSLTernaryExpression.h"
60 #include "src/sksl/ir/SkSLTypeReference.h"
61 #include "src/sksl/ir/SkSLVariableReference.h"
62
63 namespace SkSL {
64
65 namespace {
66
is_sample_call_to_fp(const FunctionCall & fc,const Variable & fp)67 static bool is_sample_call_to_fp(const FunctionCall& fc, const Variable& fp) {
68 const FunctionDeclaration& f = fc.function();
69 return f.isBuiltin() && f.name() == "sample" && fc.arguments().size() >= 1 &&
70 fc.arguments()[0]->is<VariableReference>() &&
71 fc.arguments()[0]->as<VariableReference>().variable() == &fp;
72 }
73
74 // Visitor that determines the merged SampleUsage for a given child 'fp' in the program.
75 class MergeSampleUsageVisitor : public ProgramVisitor {
76 public:
MergeSampleUsageVisitor(const Context & context,const Variable & fp,bool writesToSampleCoords)77 MergeSampleUsageVisitor(const Context& context, const Variable& fp, bool writesToSampleCoords)
78 : fContext(context), fFP(fp), fWritesToSampleCoords(writesToSampleCoords) {}
79
visit(const Program & program)80 SampleUsage visit(const Program& program) {
81 fUsage = SampleUsage(); // reset to none
82 INHERITED::visit(program);
83 return fUsage;
84 }
85
86 protected:
87 const Context& fContext;
88 const Variable& fFP;
89 const bool fWritesToSampleCoords;
90 SampleUsage fUsage;
91
visitExpression(const Expression & e)92 bool visitExpression(const Expression& e) override {
93 // Looking for sample(fp, ...)
94 if (e.is<FunctionCall>()) {
95 const FunctionCall& fc = e.as<FunctionCall>();
96 if (is_sample_call_to_fp(fc, fFP)) {
97 // Determine the type of call at this site, and merge it with the accumulated state
98 if (fc.arguments().size() >= 2) {
99 const Expression* coords = fc.arguments()[1].get();
100 if (coords->type() == *fContext.fTypes.fFloat2) {
101 // If the coords are a direct reference to the program's sample-coords,
102 // and those coords are never modified, we can conservatively turn this
103 // into PassThrough sampling. In all other cases, we consider it Explicit.
104 if (!fWritesToSampleCoords && coords->is<VariableReference>() &&
105 coords->as<VariableReference>()
106 .variable()
107 ->modifiers()
108 .fLayout.fBuiltin == SK_MAIN_COORDS_BUILTIN) {
109 fUsage.merge(SampleUsage::PassThrough());
110 } else {
111 fUsage.merge(SampleUsage::Explicit());
112 }
113 } else {
114 // sample(fp, half4 inputColor) -> PassThrough
115 fUsage.merge(SampleUsage::PassThrough());
116 }
117 } else {
118 // sample(fp) -> PassThrough
119 fUsage.merge(SampleUsage::PassThrough());
120 }
121 // NOTE: we don't return true here just because we found a sample call. We need to
122 // process the entire program and merge across all encountered calls.
123 }
124 }
125
126 return INHERITED::visitExpression(e);
127 }
128
129 using INHERITED = ProgramVisitor;
130 };
131
132 // Visitor that searches through the program for references to a particular builtin variable
133 class BuiltinVariableVisitor : public ProgramVisitor {
134 public:
BuiltinVariableVisitor(int builtin)135 BuiltinVariableVisitor(int builtin) : fBuiltin(builtin) {}
136
visitExpression(const Expression & e)137 bool visitExpression(const Expression& e) override {
138 if (e.is<VariableReference>()) {
139 const VariableReference& var = e.as<VariableReference>();
140 return var.variable()->modifiers().fLayout.fBuiltin == fBuiltin;
141 }
142 return INHERITED::visitExpression(e);
143 }
144
145 int fBuiltin;
146
147 using INHERITED = ProgramVisitor;
148 };
149
150 // Visitor that counts the number of nodes visited
151 class NodeCountVisitor : public ProgramVisitor {
152 public:
NodeCountVisitor(int limit)153 NodeCountVisitor(int limit) : fLimit(limit) {}
154
visit(const Statement & s)155 int visit(const Statement& s) {
156 this->visitStatement(s);
157 return fCount;
158 }
159
visitExpression(const Expression & e)160 bool visitExpression(const Expression& e) override {
161 ++fCount;
162 return (fCount >= fLimit) || INHERITED::visitExpression(e);
163 }
164
visitProgramElement(const ProgramElement & p)165 bool visitProgramElement(const ProgramElement& p) override {
166 ++fCount;
167 return (fCount >= fLimit) || INHERITED::visitProgramElement(p);
168 }
169
visitStatement(const Statement & s)170 bool visitStatement(const Statement& s) override {
171 ++fCount;
172 return (fCount >= fLimit) || INHERITED::visitStatement(s);
173 }
174
175 private:
176 int fCount = 0;
177 int fLimit;
178
179 using INHERITED = ProgramVisitor;
180 };
181
182 class ProgramUsageVisitor : public ProgramVisitor {
183 public:
ProgramUsageVisitor(ProgramUsage * usage,int delta)184 ProgramUsageVisitor(ProgramUsage* usage, int delta) : fUsage(usage), fDelta(delta) {}
185
visitProgramElement(const ProgramElement & pe)186 bool visitProgramElement(const ProgramElement& pe) override {
187 if (pe.is<FunctionDefinition>()) {
188 for (const Variable* param : pe.as<FunctionDefinition>().declaration().parameters()) {
189 // Ensure function-parameter variables exist in the variable usage map. They aren't
190 // otherwise declared, but ProgramUsage::get() should be able to find them, even if
191 // they are unread and unwritten.
192 fUsage->fVariableCounts[param];
193 }
194 } else if (pe.is<InterfaceBlock>()) {
195 // Ensure interface-block variables exist in the variable usage map.
196 fUsage->fVariableCounts[&pe.as<InterfaceBlock>().variable()];
197 }
198 return INHERITED::visitProgramElement(pe);
199 }
200
visitStatement(const Statement & s)201 bool visitStatement(const Statement& s) override {
202 if (s.is<VarDeclaration>()) {
203 // Add all declared variables to the usage map (even if never otherwise accessed).
204 const VarDeclaration& vd = s.as<VarDeclaration>();
205 ProgramUsage::VariableCounts& counts = fUsage->fVariableCounts[&vd.var()];
206 counts.fDeclared += fDelta;
207 SkASSERT(counts.fDeclared >= 0);
208 if (vd.value()) {
209 // The initial-value expression, when present, counts as a write.
210 counts.fWrite += fDelta;
211 }
212 }
213 return INHERITED::visitStatement(s);
214 }
215
visitExpression(const Expression & e)216 bool visitExpression(const Expression& e) override {
217 if (e.is<FunctionCall>()) {
218 const FunctionDeclaration* f = &e.as<FunctionCall>().function();
219 fUsage->fCallCounts[f] += fDelta;
220 SkASSERT(fUsage->fCallCounts[f] >= 0);
221 } else if (e.is<VariableReference>()) {
222 const VariableReference& ref = e.as<VariableReference>();
223 ProgramUsage::VariableCounts& counts = fUsage->fVariableCounts[ref.variable()];
224 switch (ref.refKind()) {
225 case VariableRefKind::kRead:
226 counts.fRead += fDelta;
227 break;
228 case VariableRefKind::kWrite:
229 counts.fWrite += fDelta;
230 break;
231 case VariableRefKind::kReadWrite:
232 case VariableRefKind::kPointer:
233 counts.fRead += fDelta;
234 counts.fWrite += fDelta;
235 break;
236 }
237 SkASSERT(counts.fRead >= 0 && counts.fWrite >= 0);
238 }
239 return INHERITED::visitExpression(e);
240 }
241
242 using ProgramVisitor::visitProgramElement;
243 using ProgramVisitor::visitStatement;
244
245 ProgramUsage* fUsage;
246 int fDelta;
247 using INHERITED = ProgramVisitor;
248 };
249
250 class VariableWriteVisitor : public ProgramVisitor {
251 public:
VariableWriteVisitor(const Variable * var)252 VariableWriteVisitor(const Variable* var)
253 : fVar(var) {}
254
visit(const Statement & s)255 bool visit(const Statement& s) {
256 return this->visitStatement(s);
257 }
258
visitExpression(const Expression & e)259 bool visitExpression(const Expression& e) override {
260 if (e.is<VariableReference>()) {
261 const VariableReference& ref = e.as<VariableReference>();
262 if (ref.variable() == fVar &&
263 (ref.refKind() == VariableReference::RefKind::kWrite ||
264 ref.refKind() == VariableReference::RefKind::kReadWrite ||
265 ref.refKind() == VariableReference::RefKind::kPointer)) {
266 return true;
267 }
268 }
269 return INHERITED::visitExpression(e);
270 }
271
272 private:
273 const Variable* fVar;
274
275 using INHERITED = ProgramVisitor;
276 };
277
278 // If a caller doesn't care about errors, we can use this trivial reporter that just counts up.
279 class TrivialErrorReporter : public ErrorReporter {
280 public:
error(int offset,String)281 void error(int offset, String) override { ++fErrorCount; }
errorCount()282 int errorCount() override { return fErrorCount; }
setErrorCount(int c)283 void setErrorCount(int c) override { fErrorCount = c; }
284
285 private:
286 int fErrorCount = 0;
287 };
288
289 // This isn't actually using ProgramVisitor, because it only considers a subset of the fields for
290 // any given expression kind. For instance, when indexing an array (e.g. `x[1]`), we only want to
291 // know if the base (`x`) is assignable; the index expression (`1`) doesn't need to be.
292 class IsAssignableVisitor {
293 public:
IsAssignableVisitor(ErrorReporter * errors)294 IsAssignableVisitor(ErrorReporter* errors) : fErrors(errors) {}
295
visit(Expression & expr,Analysis::AssignmentInfo * info)296 bool visit(Expression& expr, Analysis::AssignmentInfo* info) {
297 int oldErrorCount = fErrors->errorCount();
298 this->visitExpression(expr);
299 if (info) {
300 info->fAssignedVar = fAssignedVar;
301 }
302 return fErrors->errorCount() == oldErrorCount;
303 }
304
visitExpression(Expression & expr)305 void visitExpression(Expression& expr) {
306 switch (expr.kind()) {
307 case Expression::Kind::kVariableReference: {
308 VariableReference& varRef = expr.as<VariableReference>();
309 const Variable* var = varRef.variable();
310 if (var->modifiers().fFlags & (Modifiers::kConst_Flag | Modifiers::kUniform_Flag)) {
311 fErrors->error(expr.fOffset,
312 "cannot modify immutable variable '" + var->name() + "'");
313 } else {
314 SkASSERT(fAssignedVar == nullptr);
315 fAssignedVar = &varRef;
316 }
317 break;
318 }
319 case Expression::Kind::kFieldAccess:
320 this->visitExpression(*expr.as<FieldAccess>().base());
321 break;
322
323 case Expression::Kind::kSwizzle: {
324 const Swizzle& swizzle = expr.as<Swizzle>();
325 this->checkSwizzleWrite(swizzle);
326 this->visitExpression(*swizzle.base());
327 break;
328 }
329 case Expression::Kind::kIndex:
330 this->visitExpression(*expr.as<IndexExpression>().base());
331 break;
332
333 default:
334 fErrors->error(expr.fOffset, "cannot assign to this expression");
335 break;
336 }
337 }
338
339 private:
checkSwizzleWrite(const Swizzle & swizzle)340 void checkSwizzleWrite(const Swizzle& swizzle) {
341 int bits = 0;
342 for (int8_t idx : swizzle.components()) {
343 SkASSERT(idx >= SwizzleComponent::X && idx <= SwizzleComponent::W);
344 int bit = 1 << idx;
345 if (bits & bit) {
346 fErrors->error(swizzle.fOffset,
347 "cannot write to the same swizzle field more than once");
348 break;
349 }
350 bits |= bit;
351 }
352 }
353
354 ErrorReporter* fErrors;
355 VariableReference* fAssignedVar = nullptr;
356
357 using INHERITED = ProgramVisitor;
358 };
359
360 class SwitchCaseContainsExit : public ProgramVisitor {
361 public:
SwitchCaseContainsExit(bool conditionalExits)362 SwitchCaseContainsExit(bool conditionalExits) : fConditionalExits(conditionalExits) {}
363
visitStatement(const Statement & stmt)364 bool visitStatement(const Statement& stmt) override {
365 switch (stmt.kind()) {
366 case Statement::Kind::kBlock:
367 case Statement::Kind::kSwitchCase:
368 return INHERITED::visitStatement(stmt);
369
370 case Statement::Kind::kReturn:
371 // Returns are an early exit regardless of the surrounding control structures.
372 return fConditionalExits ? fInConditional : !fInConditional;
373
374 case Statement::Kind::kContinue:
375 // Continues are an early exit from switches, but not loops.
376 return !fInLoop &&
377 (fConditionalExits ? fInConditional : !fInConditional);
378
379 case Statement::Kind::kBreak:
380 // Breaks cannot escape from switches or loops.
381 return !fInLoop && !fInSwitch &&
382 (fConditionalExits ? fInConditional : !fInConditional);
383
384 case Statement::Kind::kIf: {
385 ++fInConditional;
386 bool result = INHERITED::visitStatement(stmt);
387 --fInConditional;
388 return result;
389 }
390
391 case Statement::Kind::kFor:
392 case Statement::Kind::kDo: {
393 // Loops are treated as conditionals because a loop could potentially execute zero
394 // times. We don't have a straightforward way to determine that a loop definitely
395 // executes at least once.
396 ++fInConditional;
397 ++fInLoop;
398 bool result = INHERITED::visitStatement(stmt);
399 --fInLoop;
400 --fInConditional;
401 return result;
402 }
403
404 case Statement::Kind::kSwitch: {
405 ++fInSwitch;
406 bool result = INHERITED::visitStatement(stmt);
407 --fInSwitch;
408 return result;
409 }
410
411 default:
412 return false;
413 }
414 }
415
416 bool fConditionalExits = false;
417 int fInConditional = 0;
418 int fInLoop = 0;
419 int fInSwitch = 0;
420 using INHERITED = ProgramVisitor;
421 };
422
423 class ReturnsOnAllPathsVisitor : public ProgramVisitor {
424 public:
visitExpression(const Expression & expr)425 bool visitExpression(const Expression& expr) override {
426 // We can avoid processing expressions entirely.
427 return false;
428 }
429
visitStatement(const Statement & stmt)430 bool visitStatement(const Statement& stmt) override {
431 switch (stmt.kind()) {
432 // Returns, breaks, or continues will stop the scan, so only one of these should ever be
433 // true.
434 case Statement::Kind::kReturn:
435 fFoundReturn = true;
436 return true;
437
438 case Statement::Kind::kBreak:
439 fFoundBreak = true;
440 return true;
441
442 case Statement::Kind::kContinue:
443 fFoundContinue = true;
444 return true;
445
446 case Statement::Kind::kIf: {
447 const IfStatement& i = stmt.as<IfStatement>();
448 ReturnsOnAllPathsVisitor trueVisitor;
449 ReturnsOnAllPathsVisitor falseVisitor;
450 trueVisitor.visitStatement(*i.ifTrue());
451 if (i.ifFalse()) {
452 falseVisitor.visitStatement(*i.ifFalse());
453 }
454 // If either branch leads to a break or continue, we report the entire if as
455 // containing a break or continue, since we don't know which side will be reached.
456 fFoundBreak = (trueVisitor.fFoundBreak || falseVisitor.fFoundBreak);
457 fFoundContinue = (trueVisitor.fFoundContinue || falseVisitor.fFoundContinue);
458 // On the other hand, we only want to report returns that definitely happen, so we
459 // require those to be found on both sides.
460 fFoundReturn = (trueVisitor.fFoundReturn && falseVisitor.fFoundReturn);
461 return fFoundBreak || fFoundContinue || fFoundReturn;
462 }
463 case Statement::Kind::kFor: {
464 const ForStatement& f = stmt.as<ForStatement>();
465 // We assume a for/while loop runs for at least one iteration; this isn't strictly
466 // guaranteed, but it's better to be slightly over-permissive here than to fail on
467 // reasonable code.
468 ReturnsOnAllPathsVisitor forVisitor;
469 forVisitor.visitStatement(*f.statement());
470 // A for loop that contains a break or continue is safe; it won't exit the entire
471 // function, just the loop. So we disregard those signals.
472 fFoundReturn = forVisitor.fFoundReturn;
473 return fFoundReturn;
474 }
475 case Statement::Kind::kDo: {
476 const DoStatement& d = stmt.as<DoStatement>();
477 // Do-while blocks are always entered at least once.
478 ReturnsOnAllPathsVisitor doVisitor;
479 doVisitor.visitStatement(*d.statement());
480 // A do-while loop that contains a break or continue is safe; it won't exit the
481 // entire function, just the loop. So we disregard those signals.
482 fFoundReturn = doVisitor.fFoundReturn;
483 return fFoundReturn;
484 }
485 case Statement::Kind::kBlock:
486 // Blocks are definitely entered and don't imply any additional control flow.
487 // If the block contains a break, continue or return, we want to keep that.
488 return INHERITED::visitStatement(stmt);
489
490 case Statement::Kind::kSwitch: {
491 // Switches are the most complex control flow we need to deal with; fortunately we
492 // already have good primitives for dissecting them. We need to verify that:
493 // - a default case exists, so that every possible input value is covered
494 // - every switch-case either (a) returns unconditionally, or
495 // (b) falls through to another case that does
496 const SwitchStatement& s = stmt.as<SwitchStatement>();
497 bool foundDefault = false;
498 bool fellThrough = false;
499 for (const std::unique_ptr<Statement>& stmt : s.cases()) {
500 // The default case is indicated by a null value. A switch without a default
501 // case cannot definitively return, as its value might not be in the cases list.
502 const SwitchCase& sc = stmt->as<SwitchCase>();
503 if (!sc.value()) {
504 foundDefault = true;
505 }
506 // Scan this switch-case for any exit (break, continue or return).
507 ReturnsOnAllPathsVisitor caseVisitor;
508 caseVisitor.visitStatement(sc);
509
510 // If we found a break or continue, whether conditional or not, this switch case
511 // can't be called an unconditional return. Switches absorb breaks but not
512 // continues.
513 if (caseVisitor.fFoundContinue) {
514 fFoundContinue = true;
515 return false;
516 }
517 if (caseVisitor.fFoundBreak) {
518 return false;
519 }
520 // We just confirmed that there weren't any breaks or continues. If we didn't
521 // find an unconditional return either, the switch is considered fallen-through.
522 // (There might be a conditional return, but that doesn't count.)
523 fellThrough = !caseVisitor.fFoundReturn;
524 }
525
526 // If we didn't find a default case, or the very last case fell through, this switch
527 // doesn't meet our criteria.
528 if (fellThrough || !foundDefault) {
529 return false;
530 }
531
532 // We scanned the entire switch, found a default case, and every section either fell
533 // through or contained an unconditional return.
534 fFoundReturn = true;
535 return true;
536 }
537
538 case Statement::Kind::kSwitchCase:
539 // Recurse into the switch-case.
540 return INHERITED::visitStatement(stmt);
541
542 case Statement::Kind::kDiscard:
543 case Statement::Kind::kExpression:
544 case Statement::Kind::kInlineMarker:
545 case Statement::Kind::kNop:
546 case Statement::Kind::kVarDeclaration:
547 // None of these statements could contain a return.
548 break;
549 }
550
551 return false;
552 }
553
554 bool fFoundReturn = false;
555 bool fFoundBreak = false;
556 bool fFoundContinue = false;
557
558 using INHERITED = ProgramVisitor;
559 };
560
561 } // namespace
562
563 ////////////////////////////////////////////////////////////////////////////////
564 // Analysis
565
GetSampleUsage(const Program & program,const Variable & fp,bool writesToSampleCoords)566 SampleUsage Analysis::GetSampleUsage(const Program& program,
567 const Variable& fp,
568 bool writesToSampleCoords) {
569 MergeSampleUsageVisitor visitor(*program.fContext, fp, writesToSampleCoords);
570 return visitor.visit(program);
571 }
572
ReferencesBuiltin(const Program & program,int builtin)573 bool Analysis::ReferencesBuiltin(const Program& program, int builtin) {
574 BuiltinVariableVisitor visitor(builtin);
575 return visitor.visit(program);
576 }
577
ReferencesSampleCoords(const Program & program)578 bool Analysis::ReferencesSampleCoords(const Program& program) {
579 return Analysis::ReferencesBuiltin(program, SK_MAIN_COORDS_BUILTIN);
580 }
581
ReferencesFragCoords(const Program & program)582 bool Analysis::ReferencesFragCoords(const Program& program) {
583 return Analysis::ReferencesBuiltin(program, SK_FRAGCOORD_BUILTIN);
584 }
585
NodeCountUpToLimit(const FunctionDefinition & function,int limit)586 int Analysis::NodeCountUpToLimit(const FunctionDefinition& function, int limit) {
587 return NodeCountVisitor{limit}.visit(*function.body());
588 }
589
SwitchCaseContainsUnconditionalExit(Statement & stmt)590 bool Analysis::SwitchCaseContainsUnconditionalExit(Statement& stmt) {
591 return SwitchCaseContainsExit{/*conditionalExits=*/false}.visitStatement(stmt);
592 }
593
SwitchCaseContainsConditionalExit(Statement & stmt)594 bool Analysis::SwitchCaseContainsConditionalExit(Statement& stmt) {
595 return SwitchCaseContainsExit{/*conditionalExits=*/true}.visitStatement(stmt);
596 }
597
GetUsage(const Program & program)598 std::unique_ptr<ProgramUsage> Analysis::GetUsage(const Program& program) {
599 auto usage = std::make_unique<ProgramUsage>();
600 ProgramUsageVisitor addRefs(usage.get(), /*delta=*/+1);
601 addRefs.visit(program);
602 return usage;
603 }
604
GetUsage(const LoadedModule & module)605 std::unique_ptr<ProgramUsage> Analysis::GetUsage(const LoadedModule& module) {
606 auto usage = std::make_unique<ProgramUsage>();
607 ProgramUsageVisitor addRefs(usage.get(), /*delta=*/+1);
608 for (const auto& element : module.fElements) {
609 addRefs.visitProgramElement(*element);
610 }
611 return usage;
612 }
613
get(const Variable & v) const614 ProgramUsage::VariableCounts ProgramUsage::get(const Variable& v) const {
615 const VariableCounts* counts = fVariableCounts.find(&v);
616 SkASSERT(counts);
617 return *counts;
618 }
619
isDead(const Variable & v) const620 bool ProgramUsage::isDead(const Variable& v) const {
621 const Modifiers& modifiers = v.modifiers();
622 VariableCounts counts = this->get(v);
623 if ((v.storage() != Variable::Storage::kLocal && counts.fRead) ||
624 (modifiers.fFlags &
625 (Modifiers::kIn_Flag | Modifiers::kOut_Flag | Modifiers::kUniform_Flag))) {
626 return false;
627 }
628 // Consider the variable dead if it's never read and never written (besides the initial-value).
629 return !counts.fRead && (counts.fWrite <= (v.initialValue() ? 1 : 0));
630 }
631
get(const FunctionDeclaration & f) const632 int ProgramUsage::get(const FunctionDeclaration& f) const {
633 const int* count = fCallCounts.find(&f);
634 return count ? *count : 0;
635 }
636
replace(const Expression * oldExpr,const Expression * newExpr)637 void ProgramUsage::replace(const Expression* oldExpr, const Expression* newExpr) {
638 if (oldExpr) {
639 ProgramUsageVisitor subRefs(this, /*delta=*/-1);
640 subRefs.visitExpression(*oldExpr);
641 }
642 if (newExpr) {
643 ProgramUsageVisitor addRefs(this, /*delta=*/+1);
644 addRefs.visitExpression(*newExpr);
645 }
646 }
647
add(const Statement * stmt)648 void ProgramUsage::add(const Statement* stmt) {
649 ProgramUsageVisitor addRefs(this, /*delta=*/+1);
650 addRefs.visitStatement(*stmt);
651 }
652
remove(const Expression * expr)653 void ProgramUsage::remove(const Expression* expr) {
654 ProgramUsageVisitor subRefs(this, /*delta=*/-1);
655 subRefs.visitExpression(*expr);
656 }
657
remove(const Statement * stmt)658 void ProgramUsage::remove(const Statement* stmt) {
659 ProgramUsageVisitor subRefs(this, /*delta=*/-1);
660 subRefs.visitStatement(*stmt);
661 }
662
remove(const ProgramElement & element)663 void ProgramUsage::remove(const ProgramElement& element) {
664 ProgramUsageVisitor subRefs(this, /*delta=*/-1);
665 subRefs.visitProgramElement(element);
666 }
667
StatementWritesToVariable(const Statement & stmt,const Variable & var)668 bool Analysis::StatementWritesToVariable(const Statement& stmt, const Variable& var) {
669 return VariableWriteVisitor(&var).visit(stmt);
670 }
671
IsAssignable(Expression & expr,AssignmentInfo * info,ErrorReporter * errors)672 bool Analysis::IsAssignable(Expression& expr, AssignmentInfo* info, ErrorReporter* errors) {
673 TrivialErrorReporter trivialErrors;
674 return IsAssignableVisitor{errors ? errors : &trivialErrors}.visit(expr, info);
675 }
676
UpdateRefKind(Expression * expr,VariableRefKind refKind)677 void Analysis::UpdateRefKind(Expression* expr, VariableRefKind refKind) {
678 class RefKindWriter : public ProgramWriter {
679 public:
680 RefKindWriter(VariableReference::RefKind refKind) : fRefKind(refKind) {}
681
682 bool visitExpression(Expression& expr) override {
683 if (expr.is<VariableReference>()) {
684 expr.as<VariableReference>().setRefKind(fRefKind);
685 }
686 return INHERITED::visitExpression(expr);
687 }
688
689 private:
690 VariableReference::RefKind fRefKind;
691
692 using INHERITED = ProgramWriter;
693 };
694
695 RefKindWriter{refKind}.visitExpression(*expr);
696 }
697
MakeAssignmentExpr(Expression * expr,VariableReference::RefKind kind,ErrorReporter * errors)698 bool Analysis::MakeAssignmentExpr(Expression* expr,
699 VariableReference::RefKind kind,
700 ErrorReporter* errors) {
701 Analysis::AssignmentInfo info;
702 if (!Analysis::IsAssignable(*expr, &info, errors)) {
703 return false;
704 }
705 if (!info.fAssignedVar) {
706 errors->error(expr->fOffset, "can't assign to expression '" + expr->description() + "'");
707 return false;
708 }
709 info.fAssignedVar->setRefKind(kind);
710 return true;
711 }
712
IsTrivialExpression(const Expression & expr)713 bool Analysis::IsTrivialExpression(const Expression& expr) {
714 return expr.is<IntLiteral>() ||
715 expr.is<FloatLiteral>() ||
716 expr.is<BoolLiteral>() ||
717 expr.is<VariableReference>() ||
718 (expr.is<Swizzle>() &&
719 IsTrivialExpression(*expr.as<Swizzle>().base())) ||
720 (expr.is<FieldAccess>() &&
721 IsTrivialExpression(*expr.as<FieldAccess>().base())) ||
722 (expr.isAnyConstructor() &&
723 expr.asAnyConstructor().argumentSpan().size() == 1 &&
724 IsTrivialExpression(*expr.asAnyConstructor().argumentSpan().front())) ||
725 (expr.isAnyConstructor() &&
726 expr.isConstantOrUniform()) ||
727 (expr.is<IndexExpression>() &&
728 expr.as<IndexExpression>().index()->is<IntLiteral>() &&
729 IsTrivialExpression(*expr.as<IndexExpression>().base()));
730 }
731
IsSameExpressionTree(const Expression & left,const Expression & right)732 bool Analysis::IsSameExpressionTree(const Expression& left, const Expression& right) {
733 if (left.kind() != right.kind() || left.type() != right.type()) {
734 return false;
735 }
736
737 // This isn't a fully exhaustive list of expressions by any stretch of the imagination; for
738 // instance, `x[y+1] = x[y+1]` isn't detected because we don't look at BinaryExpressions.
739 // Since this is intended to be used for optimization purposes, handling the common cases is
740 // sufficient.
741 switch (left.kind()) {
742 case Expression::Kind::kIntLiteral:
743 return left.as<IntLiteral>().value() == right.as<IntLiteral>().value();
744
745 case Expression::Kind::kFloatLiteral:
746 return left.as<FloatLiteral>().value() == right.as<FloatLiteral>().value();
747
748 case Expression::Kind::kBoolLiteral:
749 return left.as<BoolLiteral>().value() == right.as<BoolLiteral>().value();
750
751 case Expression::Kind::kConstructorArray:
752 case Expression::Kind::kConstructorCompound:
753 case Expression::Kind::kConstructorCompoundCast:
754 case Expression::Kind::kConstructorDiagonalMatrix:
755 case Expression::Kind::kConstructorMatrixResize:
756 case Expression::Kind::kConstructorScalarCast:
757 case Expression::Kind::kConstructorStruct:
758 case Expression::Kind::kConstructorSplat: {
759 if (left.kind() != right.kind()) {
760 return false;
761 }
762 const AnyConstructor& leftCtor = left.asAnyConstructor();
763 const AnyConstructor& rightCtor = right.asAnyConstructor();
764 const auto leftSpan = leftCtor.argumentSpan();
765 const auto rightSpan = rightCtor.argumentSpan();
766 if (leftSpan.size() != rightSpan.size()) {
767 return false;
768 }
769 for (size_t index = 0; index < leftSpan.size(); ++index) {
770 if (!IsSameExpressionTree(*leftSpan[index], *rightSpan[index])) {
771 return false;
772 }
773 }
774 return true;
775 }
776 case Expression::Kind::kFieldAccess:
777 return left.as<FieldAccess>().fieldIndex() == right.as<FieldAccess>().fieldIndex() &&
778 IsSameExpressionTree(*left.as<FieldAccess>().base(),
779 *right.as<FieldAccess>().base());
780
781 case Expression::Kind::kIndex:
782 return IsSameExpressionTree(*left.as<IndexExpression>().index(),
783 *right.as<IndexExpression>().index()) &&
784 IsSameExpressionTree(*left.as<IndexExpression>().base(),
785 *right.as<IndexExpression>().base());
786
787 case Expression::Kind::kSwizzle:
788 return left.as<Swizzle>().components() == right.as<Swizzle>().components() &&
789 IsSameExpressionTree(*left.as<Swizzle>().base(), *right.as<Swizzle>().base());
790
791 case Expression::Kind::kVariableReference:
792 return left.as<VariableReference>().variable() ==
793 right.as<VariableReference>().variable();
794
795 default:
796 return false;
797 }
798 }
799
get_constant_value(const Expression & expr,double * val)800 static bool get_constant_value(const Expression& expr, double* val) {
801 const Expression* valExpr = expr.getConstantSubexpression(0);
802 if (!valExpr) {
803 return false;
804 }
805 if (valExpr->is<IntLiteral>()) {
806 *val = static_cast<double>(valExpr->as<IntLiteral>().value());
807 return true;
808 }
809 if (valExpr->is<FloatLiteral>()) {
810 *val = static_cast<double>(valExpr->as<FloatLiteral>().value());
811 return true;
812 }
813 SkDEBUGFAILF("unexpected constant type (%s)", expr.type().description().c_str());
814 return false;
815 }
816
invalid_for_ES2(int offset,const Statement * loopInitializer,const Expression * loopTest,const Expression * loopNext,const Statement * loopStatement,Analysis::UnrollableLoopInfo & loopInfo)817 static const char* invalid_for_ES2(int offset,
818 const Statement* loopInitializer,
819 const Expression* loopTest,
820 const Expression* loopNext,
821 const Statement* loopStatement,
822 Analysis::UnrollableLoopInfo& loopInfo) {
823 //
824 // init_declaration has the form: type_specifier identifier = constant_expression
825 //
826 if (!loopInitializer) {
827 return "missing init declaration";
828 }
829 if (!loopInitializer->is<VarDeclaration>()) {
830 return "invalid init declaration";
831 }
832 const VarDeclaration& initDecl = loopInitializer->as<VarDeclaration>();
833 if (!initDecl.baseType().isNumber()) {
834 return "invalid type for loop index";
835 }
836 if (initDecl.arraySize() != 0) {
837 return "invalid type for loop index";
838 }
839 if (!initDecl.value()) {
840 return "missing loop index initializer";
841 }
842 if (!get_constant_value(*initDecl.value(), &loopInfo.fStart)) {
843 return "loop index initializer must be a constant expression";
844 }
845
846 loopInfo.fIndex = &initDecl.var();
847
848 auto is_loop_index = [&](const std::unique_ptr<Expression>& expr) {
849 return expr->is<VariableReference>() &&
850 expr->as<VariableReference>().variable() == loopInfo.fIndex;
851 };
852
853 //
854 // condition has the form: loop_index relational_operator constant_expression
855 //
856 if (!loopTest) {
857 return "missing condition";
858 }
859 if (!loopTest->is<BinaryExpression>()) {
860 return "invalid condition";
861 }
862 const BinaryExpression& cond = loopTest->as<BinaryExpression>();
863 if (!is_loop_index(cond.left())) {
864 return "expected loop index on left hand side of condition";
865 }
866 // relational_operator is one of: > >= < <= == or !=
867 switch (cond.getOperator().kind()) {
868 case Token::Kind::TK_GT:
869 case Token::Kind::TK_GTEQ:
870 case Token::Kind::TK_LT:
871 case Token::Kind::TK_LTEQ:
872 case Token::Kind::TK_EQEQ:
873 case Token::Kind::TK_NEQ:
874 break;
875 default:
876 return "invalid relational operator";
877 }
878 double loopEnd = 0;
879 if (!get_constant_value(*cond.right(), &loopEnd)) {
880 return "loop index must be compared with a constant expression";
881 }
882
883 //
884 // expression has one of the following forms:
885 // loop_index++
886 // loop_index--
887 // loop_index += constant_expression
888 // loop_index -= constant_expression
889 // The spec doesn't mention prefix increment and decrement, but there is some consensus that
890 // it's an oversight, so we allow those as well.
891 //
892 if (!loopNext) {
893 return "missing loop expression";
894 }
895 switch (loopNext->kind()) {
896 case Expression::Kind::kBinary: {
897 const BinaryExpression& next = loopNext->as<BinaryExpression>();
898 if (!is_loop_index(next.left())) {
899 return "expected loop index in loop expression";
900 }
901 if (!get_constant_value(*next.right(), &loopInfo.fDelta)) {
902 return "loop index must be modified by a constant expression";
903 }
904 switch (next.getOperator().kind()) {
905 case Token::Kind::TK_PLUSEQ: break;
906 case Token::Kind::TK_MINUSEQ: loopInfo.fDelta = -loopInfo.fDelta; break;
907 default:
908 return "invalid operator in loop expression";
909 }
910 } break;
911 case Expression::Kind::kPrefix: {
912 const PrefixExpression& next = loopNext->as<PrefixExpression>();
913 if (!is_loop_index(next.operand())) {
914 return "expected loop index in loop expression";
915 }
916 switch (next.getOperator().kind()) {
917 case Token::Kind::TK_PLUSPLUS: loopInfo.fDelta = 1; break;
918 case Token::Kind::TK_MINUSMINUS: loopInfo.fDelta = -1; break;
919 default:
920 return "invalid operator in loop expression";
921 }
922 } break;
923 case Expression::Kind::kPostfix: {
924 const PostfixExpression& next = loopNext->as<PostfixExpression>();
925 if (!is_loop_index(next.operand())) {
926 return "expected loop index in loop expression";
927 }
928 switch (next.getOperator().kind()) {
929 case Token::Kind::TK_PLUSPLUS: loopInfo.fDelta = 1; break;
930 case Token::Kind::TK_MINUSMINUS: loopInfo.fDelta = -1; break;
931 default:
932 return "invalid operator in loop expression";
933 }
934 } break;
935 default:
936 return "invalid loop expression";
937 }
938
939 //
940 // Within the body of the loop, the loop index is not statically assigned to, nor is it used as
941 // argument to a function 'out' or 'inout' parameter.
942 //
943 if (Analysis::StatementWritesToVariable(*loopStatement, initDecl.var())) {
944 return "loop index must not be modified within body of the loop";
945 }
946
947 // Finally, compute the iteration count, based on the bounds, and the termination operator.
948 constexpr int kMaxUnrollableLoopLength = 128;
949 loopInfo.fCount = 0;
950
951 double val = loopInfo.fStart;
952 auto evalCond = [&]() {
953 switch (cond.getOperator().kind()) {
954 case Token::Kind::TK_GT: return val > loopEnd;
955 case Token::Kind::TK_GTEQ: return val >= loopEnd;
956 case Token::Kind::TK_LT: return val < loopEnd;
957 case Token::Kind::TK_LTEQ: return val <= loopEnd;
958 case Token::Kind::TK_EQEQ: return val == loopEnd;
959 case Token::Kind::TK_NEQ: return val != loopEnd;
960 default: SkUNREACHABLE;
961 }
962 };
963
964 for (loopInfo.fCount = 0; loopInfo.fCount <= kMaxUnrollableLoopLength; ++loopInfo.fCount) {
965 if (!evalCond()) {
966 break;
967 }
968 val += loopInfo.fDelta;
969 }
970
971 if (loopInfo.fCount > kMaxUnrollableLoopLength) {
972 return "loop must guarantee termination in fewer iterations";
973 }
974
975 return nullptr; // All checks pass
976 }
977
ForLoopIsValidForES2(int offset,const Statement * loopInitializer,const Expression * loopTest,const Expression * loopNext,const Statement * loopStatement,Analysis::UnrollableLoopInfo * outLoopInfo,ErrorReporter * errors)978 bool Analysis::ForLoopIsValidForES2(int offset,
979 const Statement* loopInitializer,
980 const Expression* loopTest,
981 const Expression* loopNext,
982 const Statement* loopStatement,
983 Analysis::UnrollableLoopInfo* outLoopInfo,
984 ErrorReporter* errors) {
985 UnrollableLoopInfo ignored,
986 *loopInfo = outLoopInfo ? outLoopInfo : &ignored;
987 if (const char* msg = invalid_for_ES2(
988 offset, loopInitializer, loopTest, loopNext, loopStatement, *loopInfo)) {
989 if (errors) {
990 errors->error(offset, msg);
991 }
992 return false;
993 }
994 return true;
995 }
996
997 // Checks for ES2 constant-expression rules, and (optionally) constant-index-expression rules
998 // (if loopIndices is non-nullptr)
999 class ConstantExpressionVisitor : public ProgramVisitor {
1000 public:
ConstantExpressionVisitor(const std::set<const Variable * > * loopIndices)1001 ConstantExpressionVisitor(const std::set<const Variable*>* loopIndices)
1002 : fLoopIndices(loopIndices) {}
1003
visitExpression(const Expression & e)1004 bool visitExpression(const Expression& e) override {
1005 // A constant-(index)-expression is one of...
1006 switch (e.kind()) {
1007 // ... a literal value
1008 case Expression::Kind::kBoolLiteral:
1009 case Expression::Kind::kIntLiteral:
1010 case Expression::Kind::kFloatLiteral:
1011 return false;
1012
1013 // ... settings can appear in fragment processors; they will resolve when compiled
1014 case Expression::Kind::kSetting:
1015 return false;
1016
1017 // ... a global or local variable qualified as 'const', excluding function parameters.
1018 // ... loop indices as defined in section 4. [constant-index-expression]
1019 case Expression::Kind::kVariableReference: {
1020 const Variable* v = e.as<VariableReference>().variable();
1021 if ((v->storage() == Variable::Storage::kGlobal ||
1022 v->storage() == Variable::Storage::kLocal) &&
1023 (v->modifiers().fFlags & Modifiers::kConst_Flag)) {
1024 return false;
1025 }
1026 return !fLoopIndices || fLoopIndices->find(v) == fLoopIndices->end();
1027 }
1028
1029 // ... expressions composed of both of the above
1030 case Expression::Kind::kBinary:
1031 case Expression::Kind::kConstructorArray:
1032 case Expression::Kind::kConstructorCompound:
1033 case Expression::Kind::kConstructorCompoundCast:
1034 case Expression::Kind::kConstructorDiagonalMatrix:
1035 case Expression::Kind::kConstructorMatrixResize:
1036 case Expression::Kind::kConstructorScalarCast:
1037 case Expression::Kind::kConstructorSplat:
1038 case Expression::Kind::kConstructorStruct:
1039 case Expression::Kind::kFieldAccess:
1040 case Expression::Kind::kIndex:
1041 case Expression::Kind::kPrefix:
1042 case Expression::Kind::kPostfix:
1043 case Expression::Kind::kSwizzle:
1044 case Expression::Kind::kTernary:
1045 return INHERITED::visitExpression(e);
1046
1047 // These are completely disallowed in SkSL constant-(index)-expressions. GLSL allows
1048 // calls to built-in functions where the arguments are all constant-expressions, but
1049 // we don't guarantee that behavior. (skbug.com/10835)
1050 case Expression::Kind::kExternalFunctionCall:
1051 case Expression::Kind::kFunctionCall:
1052 return true;
1053
1054 // These should never appear in final IR
1055 case Expression::Kind::kExternalFunctionReference:
1056 case Expression::Kind::kFunctionReference:
1057 case Expression::Kind::kTypeReference:
1058 default:
1059 SkDEBUGFAIL("Unexpected expression type");
1060 return true;
1061 }
1062 }
1063
1064 private:
1065 const std::set<const Variable*>* fLoopIndices;
1066 using INHERITED = ProgramVisitor;
1067 };
1068
1069 class ES2IndexingVisitor : public ProgramVisitor {
1070 public:
ES2IndexingVisitor(ErrorReporter & errors)1071 ES2IndexingVisitor(ErrorReporter& errors) : fErrors(errors) {}
1072
visitStatement(const Statement & s)1073 bool visitStatement(const Statement& s) override {
1074 if (s.is<ForStatement>()) {
1075 const ForStatement& f = s.as<ForStatement>();
1076 SkASSERT(f.initializer() && f.initializer()->is<VarDeclaration>());
1077 const Variable* var = &f.initializer()->as<VarDeclaration>().var();
1078 auto [iter, inserted] = fLoopIndices.insert(var);
1079 SkASSERT(inserted);
1080 bool result = this->visitStatement(*f.statement());
1081 fLoopIndices.erase(iter);
1082 return result;
1083 }
1084 return INHERITED::visitStatement(s);
1085 }
1086
visitExpression(const Expression & e)1087 bool visitExpression(const Expression& e) override {
1088 if (e.is<IndexExpression>()) {
1089 const IndexExpression& i = e.as<IndexExpression>();
1090 ConstantExpressionVisitor indexerInvalid(&fLoopIndices);
1091 if (indexerInvalid.visitExpression(*i.index())) {
1092 fErrors.error(i.fOffset, "index expression must be constant");
1093 return true;
1094 }
1095 }
1096 return INHERITED::visitExpression(e);
1097 }
1098
1099 using ProgramVisitor::visitProgramElement;
1100
1101 private:
1102 ErrorReporter& fErrors;
1103 std::set<const Variable*> fLoopIndices;
1104 using INHERITED = ProgramVisitor;
1105 };
1106
1107
ValidateIndexingForES2(const ProgramElement & pe,ErrorReporter & errors)1108 void Analysis::ValidateIndexingForES2(const ProgramElement& pe, ErrorReporter& errors) {
1109 ES2IndexingVisitor visitor(errors);
1110 visitor.visitProgramElement(pe);
1111 }
1112
IsConstantExpression(const Expression & expr)1113 bool Analysis::IsConstantExpression(const Expression& expr) {
1114 ConstantExpressionVisitor visitor(/*loopIndices=*/nullptr);
1115 return !visitor.visitExpression(expr);
1116 }
1117
CanExitWithoutReturningValue(const FunctionDeclaration & funcDecl,const Statement & body)1118 bool Analysis::CanExitWithoutReturningValue(const FunctionDeclaration& funcDecl,
1119 const Statement& body) {
1120 if (funcDecl.returnType().isVoid()) {
1121 return false;
1122 }
1123 ReturnsOnAllPathsVisitor visitor;
1124 visitor.visitStatement(body);
1125 return !visitor.fFoundReturn;
1126 }
1127
1128 ////////////////////////////////////////////////////////////////////////////////
1129 // ProgramVisitor
1130
visit(const Program & program)1131 bool ProgramVisitor::visit(const Program& program) {
1132 for (const ProgramElement* pe : program.elements()) {
1133 if (this->visitProgramElement(*pe)) {
1134 return true;
1135 }
1136 }
1137 return false;
1138 }
1139
visitExpression(typename T::Expression & e)1140 template <typename T> bool TProgramVisitor<T>::visitExpression(typename T::Expression& e) {
1141 switch (e.kind()) {
1142 case Expression::Kind::kBoolLiteral:
1143 case Expression::Kind::kExternalFunctionReference:
1144 case Expression::Kind::kFloatLiteral:
1145 case Expression::Kind::kFunctionReference:
1146 case Expression::Kind::kIntLiteral:
1147 case Expression::Kind::kSetting:
1148 case Expression::Kind::kTypeReference:
1149 case Expression::Kind::kVariableReference:
1150 // Leaf expressions return false
1151 return false;
1152
1153 case Expression::Kind::kBinary: {
1154 auto& b = e.template as<BinaryExpression>();
1155 return (b.left() && this->visitExpressionPtr(b.left())) ||
1156 (b.right() && this->visitExpressionPtr(b.right()));
1157 }
1158 case Expression::Kind::kConstructorArray:
1159 case Expression::Kind::kConstructorCompound:
1160 case Expression::Kind::kConstructorCompoundCast:
1161 case Expression::Kind::kConstructorDiagonalMatrix:
1162 case Expression::Kind::kConstructorMatrixResize:
1163 case Expression::Kind::kConstructorScalarCast:
1164 case Expression::Kind::kConstructorSplat:
1165 case Expression::Kind::kConstructorStruct: {
1166 auto& c = e.asAnyConstructor();
1167 for (auto& arg : c.argumentSpan()) {
1168 if (this->visitExpressionPtr(arg)) { return true; }
1169 }
1170 return false;
1171 }
1172 case Expression::Kind::kExternalFunctionCall: {
1173 auto& c = e.template as<ExternalFunctionCall>();
1174 for (auto& arg : c.arguments()) {
1175 if (this->visitExpressionPtr(arg)) { return true; }
1176 }
1177 return false;
1178 }
1179 case Expression::Kind::kFieldAccess:
1180 return this->visitExpressionPtr(e.template as<FieldAccess>().base());
1181
1182 case Expression::Kind::kFunctionCall: {
1183 auto& c = e.template as<FunctionCall>();
1184 for (auto& arg : c.arguments()) {
1185 if (arg && this->visitExpressionPtr(arg)) { return true; }
1186 }
1187 return false;
1188 }
1189 case Expression::Kind::kIndex: {
1190 auto& i = e.template as<IndexExpression>();
1191 return this->visitExpressionPtr(i.base()) || this->visitExpressionPtr(i.index());
1192 }
1193 case Expression::Kind::kPostfix:
1194 return this->visitExpressionPtr(e.template as<PostfixExpression>().operand());
1195
1196 case Expression::Kind::kPrefix:
1197 return this->visitExpressionPtr(e.template as<PrefixExpression>().operand());
1198
1199 case Expression::Kind::kSwizzle: {
1200 auto& s = e.template as<Swizzle>();
1201 return s.base() && this->visitExpressionPtr(s.base());
1202 }
1203
1204 case Expression::Kind::kTernary: {
1205 auto& t = e.template as<TernaryExpression>();
1206 return this->visitExpressionPtr(t.test()) ||
1207 (t.ifTrue() && this->visitExpressionPtr(t.ifTrue())) ||
1208 (t.ifFalse() && this->visitExpressionPtr(t.ifFalse()));
1209 }
1210 default:
1211 SkUNREACHABLE;
1212 }
1213 }
1214
visitStatement(typename T::Statement & s)1215 template <typename T> bool TProgramVisitor<T>::visitStatement(typename T::Statement& s) {
1216 switch (s.kind()) {
1217 case Statement::Kind::kBreak:
1218 case Statement::Kind::kContinue:
1219 case Statement::Kind::kDiscard:
1220 case Statement::Kind::kInlineMarker:
1221 case Statement::Kind::kNop:
1222 // Leaf statements just return false
1223 return false;
1224
1225 case Statement::Kind::kBlock:
1226 for (auto& stmt : s.template as<Block>().children()) {
1227 if (stmt && this->visitStatementPtr(stmt)) {
1228 return true;
1229 }
1230 }
1231 return false;
1232
1233 case Statement::Kind::kSwitchCase: {
1234 auto& sc = s.template as<SwitchCase>();
1235 if (sc.value() && this->visitExpressionPtr(sc.value())) {
1236 return true;
1237 }
1238 return this->visitStatementPtr(sc.statement());
1239 }
1240 case Statement::Kind::kDo: {
1241 auto& d = s.template as<DoStatement>();
1242 return this->visitExpressionPtr(d.test()) || this->visitStatementPtr(d.statement());
1243 }
1244 case Statement::Kind::kExpression:
1245 return this->visitExpressionPtr(s.template as<ExpressionStatement>().expression());
1246
1247 case Statement::Kind::kFor: {
1248 auto& f = s.template as<ForStatement>();
1249 return (f.initializer() && this->visitStatementPtr(f.initializer())) ||
1250 (f.test() && this->visitExpressionPtr(f.test())) ||
1251 (f.next() && this->visitExpressionPtr(f.next())) ||
1252 this->visitStatementPtr(f.statement());
1253 }
1254 case Statement::Kind::kIf: {
1255 auto& i = s.template as<IfStatement>();
1256 return (i.test() && this->visitExpressionPtr(i.test())) ||
1257 (i.ifTrue() && this->visitStatementPtr(i.ifTrue())) ||
1258 (i.ifFalse() && this->visitStatementPtr(i.ifFalse()));
1259 }
1260 case Statement::Kind::kReturn: {
1261 auto& r = s.template as<ReturnStatement>();
1262 return r.expression() && this->visitExpressionPtr(r.expression());
1263 }
1264 case Statement::Kind::kSwitch: {
1265 auto& sw = s.template as<SwitchStatement>();
1266 if (this->visitExpressionPtr(sw.value())) {
1267 return true;
1268 }
1269 for (auto& c : sw.cases()) {
1270 if (this->visitStatementPtr(c)) {
1271 return true;
1272 }
1273 }
1274 return false;
1275 }
1276 case Statement::Kind::kVarDeclaration: {
1277 auto& v = s.template as<VarDeclaration>();
1278 return v.value() && this->visitExpressionPtr(v.value());
1279 }
1280 default:
1281 SkUNREACHABLE;
1282 }
1283 }
1284
visitProgramElement(typename T::ProgramElement & pe)1285 template <typename T> bool TProgramVisitor<T>::visitProgramElement(typename T::ProgramElement& pe) {
1286 switch (pe.kind()) {
1287 case ProgramElement::Kind::kEnum:
1288 case ProgramElement::Kind::kExtension:
1289 case ProgramElement::Kind::kFunctionPrototype:
1290 case ProgramElement::Kind::kInterfaceBlock:
1291 case ProgramElement::Kind::kModifiers:
1292 case ProgramElement::Kind::kSection:
1293 case ProgramElement::Kind::kStructDefinition:
1294 // Leaf program elements just return false by default
1295 return false;
1296
1297 case ProgramElement::Kind::kFunction:
1298 return this->visitStatementPtr(pe.template as<FunctionDefinition>().body());
1299
1300 case ProgramElement::Kind::kGlobalVar:
1301 return this->visitStatementPtr(pe.template as<GlobalVarDeclaration>().declaration());
1302
1303 default:
1304 SkUNREACHABLE;
1305 }
1306 }
1307
1308 template class TProgramVisitor<ProgramVisitorTypes>;
1309 template class TProgramVisitor<ProgramWriterTypes>;
1310
1311 } // namespace SkSL
1312