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/SkFloatingPoint.h"
11 #include "include/private/SkSLModifiers.h"
12 #include "include/private/SkSLProgramElement.h"
13 #include "include/private/SkSLSampleUsage.h"
14 #include "include/private/SkSLStatement.h"
15 #include "include/sksl/SkSLErrorReporter.h"
16 #include "src/core/SkSafeMath.h"
17 #include "src/sksl/SkSLCompiler.h"
18 #include "src/sksl/SkSLConstantFolder.h"
19 #include "src/sksl/analysis/SkSLProgramVisitor.h"
20 #include "src/sksl/ir/SkSLExpression.h"
21 #include "src/sksl/ir/SkSLProgram.h"
22 #include "src/sksl/transform/SkSLProgramWriter.h"
23
24 // ProgramElements
25 #include "src/sksl/ir/SkSLExtension.h"
26 #include "src/sksl/ir/SkSLFunctionDefinition.h"
27 #include "src/sksl/ir/SkSLInterfaceBlock.h"
28 #include "src/sksl/ir/SkSLVarDeclarations.h"
29
30 // Statements
31 #include "src/sksl/ir/SkSLBlock.h"
32 #include "src/sksl/ir/SkSLBreakStatement.h"
33 #include "src/sksl/ir/SkSLContinueStatement.h"
34 #include "src/sksl/ir/SkSLDiscardStatement.h"
35 #include "src/sksl/ir/SkSLDoStatement.h"
36 #include "src/sksl/ir/SkSLExpressionStatement.h"
37 #include "src/sksl/ir/SkSLForStatement.h"
38 #include "src/sksl/ir/SkSLIfStatement.h"
39 #include "src/sksl/ir/SkSLNop.h"
40 #include "src/sksl/ir/SkSLReturnStatement.h"
41 #include "src/sksl/ir/SkSLSwitchStatement.h"
42
43 // Expressions
44 #include "src/sksl/ir/SkSLBinaryExpression.h"
45 #include "src/sksl/ir/SkSLChildCall.h"
46 #include "src/sksl/ir/SkSLConstructor.h"
47 #include "src/sksl/ir/SkSLConstructorDiagonalMatrix.h"
48 #include "src/sksl/ir/SkSLConstructorMatrixResize.h"
49 #include "src/sksl/ir/SkSLExternalFunctionCall.h"
50 #include "src/sksl/ir/SkSLExternalFunctionReference.h"
51 #include "src/sksl/ir/SkSLFieldAccess.h"
52 #include "src/sksl/ir/SkSLFunctionCall.h"
53 #include "src/sksl/ir/SkSLFunctionReference.h"
54 #include "src/sksl/ir/SkSLIndexExpression.h"
55 #include "src/sksl/ir/SkSLInlineMarker.h"
56 #include "src/sksl/ir/SkSLLiteral.h"
57 #include "src/sksl/ir/SkSLPostfixExpression.h"
58 #include "src/sksl/ir/SkSLPrefixExpression.h"
59 #include "src/sksl/ir/SkSLSetting.h"
60 #include "src/sksl/ir/SkSLSwizzle.h"
61 #include "src/sksl/ir/SkSLTernaryExpression.h"
62 #include "src/sksl/ir/SkSLTypeReference.h"
63 #include "src/sksl/ir/SkSLVariableReference.h"
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 bool fWritesToSampleCoords;
89 SampleUsage fUsage;
90 int fElidedSampleCoordCount = 0;
91
visitExpression(const Expression & e)92 bool visitExpression(const Expression& e) override {
93 // Looking for child(...)
94 if (e.is<ChildCall>() && &e.as<ChildCall>().child() == &fChild) {
95 // Determine the type of call at this site, and merge it with the accumulated state
96 const ExpressionArray& arguments = e.as<ChildCall>().arguments();
97 SkASSERT(arguments.size() >= 1);
98
99 const Expression* maybeCoords = arguments[0].get();
100 if (maybeCoords->type() == *fContext.fTypes.fFloat2) {
101 // If the coords are a direct reference to the program's sample-coords, and those
102 // coords are never modified, we can conservatively turn this into PassThrough
103 // sampling. In all other cases, we consider it Explicit.
104 if (!fWritesToSampleCoords && maybeCoords->is<VariableReference>() &&
105 maybeCoords->as<VariableReference>().variable()->modifiers().fLayout.fBuiltin ==
106 SK_MAIN_COORDS_BUILTIN) {
107 fUsage.merge(SampleUsage::PassThrough());
108 ++fElidedSampleCoordCount;
109 } else {
110 fUsage.merge(SampleUsage::Explicit());
111 }
112 } else {
113 // child(inputColor) or child(srcColor, dstColor) -> PassThrough
114 fUsage.merge(SampleUsage::PassThrough());
115 }
116 }
117
118 return INHERITED::visitExpression(e);
119 }
120
121 using INHERITED = ProgramVisitor;
122 };
123
124 // Visitor that searches through the program for references to a particular builtin variable
125 class BuiltinVariableVisitor : public ProgramVisitor {
126 public:
BuiltinVariableVisitor(int builtin)127 BuiltinVariableVisitor(int builtin) : fBuiltin(builtin) {}
128
visitExpression(const Expression & e)129 bool visitExpression(const Expression& e) override {
130 if (e.is<VariableReference>()) {
131 const VariableReference& var = e.as<VariableReference>();
132 return var.variable()->modifiers().fLayout.fBuiltin == fBuiltin;
133 }
134 return INHERITED::visitExpression(e);
135 }
136
137 int fBuiltin;
138
139 using INHERITED = ProgramVisitor;
140 };
141
142 // Visitor that searches for child calls from a function other than main()
143 class SampleOutsideMainVisitor : public ProgramVisitor {
144 public:
SampleOutsideMainVisitor()145 SampleOutsideMainVisitor() {}
146
visitExpression(const Expression & e)147 bool visitExpression(const Expression& e) override {
148 if (e.is<ChildCall>()) {
149 return true;
150 }
151 return INHERITED::visitExpression(e);
152 }
153
visitProgramElement(const ProgramElement & p)154 bool visitProgramElement(const ProgramElement& p) override {
155 return p.is<FunctionDefinition>() &&
156 !p.as<FunctionDefinition>().declaration().isMain() &&
157 INHERITED::visitProgramElement(p);
158 }
159
160 using INHERITED = ProgramVisitor;
161 };
162
163 // Visitor that counts the number of nodes visited
164 class NodeCountVisitor : public ProgramVisitor {
165 public:
NodeCountVisitor(int limit)166 NodeCountVisitor(int limit) : fLimit(limit) {}
167
visit(const Statement & s)168 int visit(const Statement& s) {
169 this->visitStatement(s);
170 return fCount;
171 }
172
visitExpression(const Expression & e)173 bool visitExpression(const Expression& e) override {
174 ++fCount;
175 return (fCount >= fLimit) || INHERITED::visitExpression(e);
176 }
177
visitProgramElement(const ProgramElement & p)178 bool visitProgramElement(const ProgramElement& p) override {
179 ++fCount;
180 return (fCount >= fLimit) || INHERITED::visitProgramElement(p);
181 }
182
visitStatement(const Statement & s)183 bool visitStatement(const Statement& s) override {
184 ++fCount;
185 return (fCount >= fLimit) || INHERITED::visitStatement(s);
186 }
187
188 private:
189 int fCount = 0;
190 int fLimit;
191
192 using INHERITED = ProgramVisitor;
193 };
194
195 class VariableWriteVisitor : public ProgramVisitor {
196 public:
VariableWriteVisitor(const Variable * var)197 VariableWriteVisitor(const Variable* var)
198 : fVar(var) {}
199
visit(const Statement & s)200 bool visit(const Statement& s) {
201 return this->visitStatement(s);
202 }
203
visitExpression(const Expression & e)204 bool visitExpression(const Expression& e) override {
205 if (e.is<VariableReference>()) {
206 const VariableReference& ref = e.as<VariableReference>();
207 if (ref.variable() == fVar &&
208 (ref.refKind() == VariableReference::RefKind::kWrite ||
209 ref.refKind() == VariableReference::RefKind::kReadWrite ||
210 ref.refKind() == VariableReference::RefKind::kPointer)) {
211 return true;
212 }
213 }
214 return INHERITED::visitExpression(e);
215 }
216
217 private:
218 const Variable* fVar;
219
220 using INHERITED = ProgramVisitor;
221 };
222
223 // If a caller doesn't care about errors, we can use this trivial reporter that just counts up.
224 class TrivialErrorReporter : public ErrorReporter {
225 public:
~TrivialErrorReporter()226 ~TrivialErrorReporter() override { this->reportPendingErrors({}); }
handleError(skstd::string_view,PositionInfo)227 void handleError(skstd::string_view, PositionInfo) override {}
228 };
229
230 // This isn't actually using ProgramVisitor, because it only considers a subset of the fields for
231 // any given expression kind. For instance, when indexing an array (e.g. `x[1]`), we only want to
232 // know if the base (`x`) is assignable; the index expression (`1`) doesn't need to be.
233 class IsAssignableVisitor {
234 public:
IsAssignableVisitor(ErrorReporter * errors)235 IsAssignableVisitor(ErrorReporter* errors) : fErrors(errors) {}
236
visit(Expression & expr,Analysis::AssignmentInfo * info)237 bool visit(Expression& expr, Analysis::AssignmentInfo* info) {
238 int oldErrorCount = fErrors->errorCount();
239 this->visitExpression(expr);
240 if (info) {
241 info->fAssignedVar = fAssignedVar;
242 }
243 return fErrors->errorCount() == oldErrorCount;
244 }
245
visitExpression(Expression & expr)246 void visitExpression(Expression& expr) {
247 switch (expr.kind()) {
248 case Expression::Kind::kVariableReference: {
249 VariableReference& varRef = expr.as<VariableReference>();
250 const Variable* var = varRef.variable();
251 if (var->modifiers().fFlags & (Modifiers::kConst_Flag | Modifiers::kUniform_Flag)) {
252 fErrors->error(expr.fLine,
253 "cannot modify immutable variable '" + var->name() + "'");
254 } else {
255 SkASSERT(fAssignedVar == nullptr);
256 fAssignedVar = &varRef;
257 }
258 break;
259 }
260 case Expression::Kind::kFieldAccess:
261 this->visitExpression(*expr.as<FieldAccess>().base());
262 break;
263
264 case Expression::Kind::kSwizzle: {
265 const Swizzle& swizzle = expr.as<Swizzle>();
266 this->checkSwizzleWrite(swizzle);
267 this->visitExpression(*swizzle.base());
268 break;
269 }
270 case Expression::Kind::kIndex:
271 this->visitExpression(*expr.as<IndexExpression>().base());
272 break;
273
274 case Expression::Kind::kPoison:
275 break;
276
277 default:
278 fErrors->error(expr.fLine, "cannot assign to this expression");
279 break;
280 }
281 }
282
283 private:
checkSwizzleWrite(const Swizzle & swizzle)284 void checkSwizzleWrite(const Swizzle& swizzle) {
285 int bits = 0;
286 for (int8_t idx : swizzle.components()) {
287 SkASSERT(idx >= SwizzleComponent::X && idx <= SwizzleComponent::W);
288 int bit = 1 << idx;
289 if (bits & bit) {
290 fErrors->error(swizzle.fLine,
291 "cannot write to the same swizzle field more than once");
292 break;
293 }
294 bits |= bit;
295 }
296 }
297
298 ErrorReporter* fErrors;
299 VariableReference* fAssignedVar = nullptr;
300
301 using INHERITED = ProgramVisitor;
302 };
303
304 } // namespace
305
306 ////////////////////////////////////////////////////////////////////////////////
307 // Analysis
308
GetSampleUsage(const Program & program,const Variable & child,bool writesToSampleCoords,int * elidedSampleCoordCount)309 SampleUsage Analysis::GetSampleUsage(const Program& program,
310 const Variable& child,
311 bool writesToSampleCoords,
312 int* elidedSampleCoordCount) {
313 MergeSampleUsageVisitor visitor(*program.fContext, child, writesToSampleCoords);
314 SampleUsage result = visitor.visit(program);
315 if (elidedSampleCoordCount) {
316 *elidedSampleCoordCount += visitor.elidedSampleCoordCount();
317 }
318 return result;
319 }
320
ReferencesBuiltin(const Program & program,int builtin)321 bool Analysis::ReferencesBuiltin(const Program& program, int builtin) {
322 BuiltinVariableVisitor visitor(builtin);
323 return visitor.visit(program);
324 }
325
ReferencesSampleCoords(const Program & program)326 bool Analysis::ReferencesSampleCoords(const Program& program) {
327 return Analysis::ReferencesBuiltin(program, SK_MAIN_COORDS_BUILTIN);
328 }
329
ReferencesFragCoords(const Program & program)330 bool Analysis::ReferencesFragCoords(const Program& program) {
331 return Analysis::ReferencesBuiltin(program, SK_FRAGCOORD_BUILTIN);
332 }
333
CallsSampleOutsideMain(const Program & program)334 bool Analysis::CallsSampleOutsideMain(const Program& program) {
335 SampleOutsideMainVisitor visitor;
336 return visitor.visit(program);
337 }
338
DetectVarDeclarationWithoutScope(const Statement & stmt,ErrorReporter * errors)339 bool Analysis::DetectVarDeclarationWithoutScope(const Statement& stmt, ErrorReporter* errors) {
340 // A variable declaration can create either a lone VarDeclaration or an unscoped Block
341 // containing multiple VarDeclaration statements. We need to detect either case.
342 const Variable* var;
343 if (stmt.is<VarDeclaration>()) {
344 // The single-variable case. No blocks at all.
345 var = &stmt.as<VarDeclaration>().var();
346 } else if (stmt.is<Block>()) {
347 // The multiple-variable case: an unscoped, non-empty block...
348 const Block& block = stmt.as<Block>();
349 if (block.isScope() || block.children().empty()) {
350 return false;
351 }
352 // ... holding a variable declaration.
353 const Statement& innerStmt = *block.children().front();
354 if (!innerStmt.is<VarDeclaration>()) {
355 return false;
356 }
357 var = &innerStmt.as<VarDeclaration>().var();
358 } else {
359 // This statement wasn't a variable declaration. No problem.
360 return false;
361 }
362
363 // Report an error.
364 SkASSERT(var);
365 if (errors) {
366 errors->error(stmt.fLine, "variable '" + var->name() + "' must be created in a scope");
367 }
368 return true;
369 }
370
NodeCountUpToLimit(const FunctionDefinition & function,int limit)371 int Analysis::NodeCountUpToLimit(const FunctionDefinition& function, int limit) {
372 return NodeCountVisitor{limit}.visit(*function.body());
373 }
374
StatementWritesToVariable(const Statement & stmt,const Variable & var)375 bool Analysis::StatementWritesToVariable(const Statement& stmt, const Variable& var) {
376 return VariableWriteVisitor(&var).visit(stmt);
377 }
378
IsAssignable(Expression & expr,AssignmentInfo * info,ErrorReporter * errors)379 bool Analysis::IsAssignable(Expression& expr, AssignmentInfo* info, ErrorReporter* errors) {
380 TrivialErrorReporter trivialErrors;
381 return IsAssignableVisitor{errors ? errors : &trivialErrors}.visit(expr, info);
382 }
383
UpdateVariableRefKind(Expression * expr,VariableReference::RefKind kind,ErrorReporter * errors)384 bool Analysis::UpdateVariableRefKind(Expression* expr,
385 VariableReference::RefKind kind,
386 ErrorReporter* errors) {
387 Analysis::AssignmentInfo info;
388 if (!Analysis::IsAssignable(*expr, &info, errors)) {
389 return false;
390 }
391 if (!info.fAssignedVar) {
392 if (errors) {
393 errors->error(expr->fLine, "can't assign to expression '" + expr->description() + "'");
394 }
395 return false;
396 }
397 info.fAssignedVar->setRefKind(kind);
398 return true;
399 }
400
IsTrivialExpression(const Expression & expr)401 bool Analysis::IsTrivialExpression(const Expression& expr) {
402 return expr.is<Literal>() ||
403 expr.is<VariableReference>() ||
404 (expr.is<Swizzle>() &&
405 IsTrivialExpression(*expr.as<Swizzle>().base())) ||
406 (expr.is<FieldAccess>() &&
407 IsTrivialExpression(*expr.as<FieldAccess>().base())) ||
408 (expr.isAnyConstructor() &&
409 expr.asAnyConstructor().argumentSpan().size() == 1 &&
410 IsTrivialExpression(*expr.asAnyConstructor().argumentSpan().front())) ||
411 (expr.isAnyConstructor() &&
412 expr.isConstantOrUniform()) ||
413 (expr.is<IndexExpression>() &&
414 expr.as<IndexExpression>().index()->isIntLiteral() &&
415 IsTrivialExpression(*expr.as<IndexExpression>().base()));
416 }
417
IsSameExpressionTree(const Expression & left,const Expression & right)418 bool Analysis::IsSameExpressionTree(const Expression& left, const Expression& right) {
419 if (left.kind() != right.kind() || left.type() != right.type()) {
420 return false;
421 }
422
423 // This isn't a fully exhaustive list of expressions by any stretch of the imagination; for
424 // instance, `x[y+1] = x[y+1]` isn't detected because we don't look at BinaryExpressions.
425 // Since this is intended to be used for optimization purposes, handling the common cases is
426 // sufficient.
427 switch (left.kind()) {
428 case Expression::Kind::kLiteral:
429 return left.as<Literal>().value() == right.as<Literal>().value();
430
431 case Expression::Kind::kConstructorArray:
432 case Expression::Kind::kConstructorArrayCast:
433 case Expression::Kind::kConstructorCompound:
434 case Expression::Kind::kConstructorCompoundCast:
435 case Expression::Kind::kConstructorDiagonalMatrix:
436 case Expression::Kind::kConstructorMatrixResize:
437 case Expression::Kind::kConstructorScalarCast:
438 case Expression::Kind::kConstructorStruct:
439 case Expression::Kind::kConstructorSplat: {
440 if (left.kind() != right.kind()) {
441 return false;
442 }
443 const AnyConstructor& leftCtor = left.asAnyConstructor();
444 const AnyConstructor& rightCtor = right.asAnyConstructor();
445 const auto leftSpan = leftCtor.argumentSpan();
446 const auto rightSpan = rightCtor.argumentSpan();
447 if (leftSpan.size() != rightSpan.size()) {
448 return false;
449 }
450 for (size_t index = 0; index < leftSpan.size(); ++index) {
451 if (!IsSameExpressionTree(*leftSpan[index], *rightSpan[index])) {
452 return false;
453 }
454 }
455 return true;
456 }
457 case Expression::Kind::kFieldAccess:
458 return left.as<FieldAccess>().fieldIndex() == right.as<FieldAccess>().fieldIndex() &&
459 IsSameExpressionTree(*left.as<FieldAccess>().base(),
460 *right.as<FieldAccess>().base());
461
462 case Expression::Kind::kIndex:
463 return IsSameExpressionTree(*left.as<IndexExpression>().index(),
464 *right.as<IndexExpression>().index()) &&
465 IsSameExpressionTree(*left.as<IndexExpression>().base(),
466 *right.as<IndexExpression>().base());
467
468 case Expression::Kind::kSwizzle:
469 return left.as<Swizzle>().components() == right.as<Swizzle>().components() &&
470 IsSameExpressionTree(*left.as<Swizzle>().base(), *right.as<Swizzle>().base());
471
472 case Expression::Kind::kVariableReference:
473 return left.as<VariableReference>().variable() ==
474 right.as<VariableReference>().variable();
475
476 default:
477 return false;
478 }
479 }
480
481 class ES2IndexingVisitor : public ProgramVisitor {
482 public:
ES2IndexingVisitor(ErrorReporter & errors)483 ES2IndexingVisitor(ErrorReporter& errors) : fErrors(errors) {}
484
visitStatement(const Statement & s)485 bool visitStatement(const Statement& s) override {
486 if (s.is<ForStatement>()) {
487 const ForStatement& f = s.as<ForStatement>();
488 SkASSERT(f.initializer() && f.initializer()->is<VarDeclaration>());
489 const Variable* var = &f.initializer()->as<VarDeclaration>().var();
490 auto [iter, inserted] = fLoopIndices.insert(var);
491 SkASSERT(inserted);
492 bool result = this->visitStatement(*f.statement());
493 fLoopIndices.erase(iter);
494 return result;
495 }
496 return INHERITED::visitStatement(s);
497 }
498
visitExpression(const Expression & e)499 bool visitExpression(const Expression& e) override {
500 if (e.is<IndexExpression>()) {
501 const IndexExpression& i = e.as<IndexExpression>();
502 if (!Analysis::IsConstantIndexExpression(*i.index(), &fLoopIndices)) {
503 fErrors.error(i.fLine, "index expression must be constant");
504 return true;
505 }
506 }
507 return INHERITED::visitExpression(e);
508 }
509
510 using ProgramVisitor::visitProgramElement;
511
512 private:
513 ErrorReporter& fErrors;
514 std::set<const Variable*> fLoopIndices;
515 using INHERITED = ProgramVisitor;
516 };
517
ValidateIndexingForES2(const ProgramElement & pe,ErrorReporter & errors)518 void Analysis::ValidateIndexingForES2(const ProgramElement& pe, ErrorReporter& errors) {
519 ES2IndexingVisitor visitor(errors);
520 visitor.visitProgramElement(pe);
521 }
522
VerifyStaticTestsAndExpressions(const Program & program)523 void Analysis::VerifyStaticTestsAndExpressions(const Program& program) {
524 class TestsAndExpressions : public ProgramVisitor {
525 public:
526 TestsAndExpressions(const Context& ctx) : fContext(ctx) {}
527
528 bool visitProgramElement(const ProgramElement& pe) override {
529 if (pe.kind() == ProgramElement::Kind::kGlobalVar) {
530 const VarDeclaration& decl =
531 pe.as<GlobalVarDeclaration>().declaration()->as<VarDeclaration>();
532
533 size_t prevSlotsUsed = fGlobalSlotsUsed;
534 fGlobalSlotsUsed = SkSafeMath::Add(fGlobalSlotsUsed, decl.var().type().slotCount());
535 // To avoid overzealous error reporting, only trigger the error at the first
536 // place where the global limit is exceeded.
537 if (prevSlotsUsed < kVariableSlotLimit && fGlobalSlotsUsed >= kVariableSlotLimit) {
538 fContext.fErrors->error(pe.fLine, "global variable '" + decl.var().name() +
539 "' exceeds the size limit");
540 }
541 }
542 return INHERITED::visitProgramElement(pe);
543 }
544
545 bool visitStatement(const Statement& stmt) override {
546 if (!fContext.fConfig->fSettings.fPermitInvalidStaticTests) {
547 switch (stmt.kind()) {
548 case Statement::Kind::kIf:
549 if (stmt.as<IfStatement>().isStatic()) {
550 fContext.fErrors->error(stmt.fLine, "static if has non-static test");
551 }
552 break;
553
554 case Statement::Kind::kSwitch:
555 if (stmt.as<SwitchStatement>().isStatic()) {
556 fContext.fErrors->error(stmt.fLine,
557 "static switch has non-static test");
558 }
559 break;
560
561 default:
562 break;
563 }
564 }
565 return INHERITED::visitStatement(stmt);
566 }
567
568 bool visitExpression(const Expression& expr) override {
569 switch (expr.kind()) {
570 case Expression::Kind::kFunctionCall: {
571 const FunctionDeclaration& decl = expr.as<FunctionCall>().function();
572 if (!decl.isBuiltin() && !decl.definition()) {
573 fContext.fErrors->error(expr.fLine, "function '" + decl.description() +
574 "' is not defined");
575 }
576 break;
577 }
578 case Expression::Kind::kExternalFunctionReference:
579 case Expression::Kind::kFunctionReference:
580 case Expression::Kind::kMethodReference:
581 case Expression::Kind::kTypeReference:
582 SkDEBUGFAIL("invalid reference-expr, should have been reported by coerce()");
583 fContext.fErrors->error(expr.fLine, "invalid expression");
584 break;
585 default:
586 if (expr.type() == *fContext.fTypes.fInvalid) {
587 fContext.fErrors->error(expr.fLine, "invalid expression");
588 }
589 break;
590 }
591 return INHERITED::visitExpression(expr);
592 }
593
594 private:
595 using INHERITED = ProgramVisitor;
596 size_t fGlobalSlotsUsed = 0;
597 const Context& fContext;
598 };
599
600 // Check all of the program's owned elements. (Built-in elements are assumed to be valid.)
601 TestsAndExpressions visitor{*program.fContext};
602 for (const std::unique_ptr<ProgramElement>& element : program.fOwnedElements) {
603 visitor.visitProgramElement(*element);
604 }
605 }
606
607 ////////////////////////////////////////////////////////////////////////////////
608 // ProgramVisitor
609
visit(const Program & program)610 bool ProgramVisitor::visit(const Program& program) {
611 for (const ProgramElement* pe : program.elements()) {
612 if (this->visitProgramElement(*pe)) {
613 return true;
614 }
615 }
616 return false;
617 }
618
visitExpression(typename T::Expression & e)619 template <typename T> bool TProgramVisitor<T>::visitExpression(typename T::Expression& e) {
620 switch (e.kind()) {
621 case Expression::Kind::kCodeString:
622 case Expression::Kind::kExternalFunctionReference:
623 case Expression::Kind::kFunctionReference:
624 case Expression::Kind::kLiteral:
625 case Expression::Kind::kMethodReference:
626 case Expression::Kind::kPoison:
627 case Expression::Kind::kSetting:
628 case Expression::Kind::kTypeReference:
629 case Expression::Kind::kVariableReference:
630 // Leaf expressions return false
631 return false;
632
633 case Expression::Kind::kBinary: {
634 auto& b = e.template as<BinaryExpression>();
635 return (b.left() && this->visitExpressionPtr(b.left())) ||
636 (b.right() && this->visitExpressionPtr(b.right()));
637 }
638 case Expression::Kind::kChildCall: {
639 // We don't visit the child variable itself, just the arguments
640 auto& c = e.template as<ChildCall>();
641 for (auto& arg : c.arguments()) {
642 if (arg && this->visitExpressionPtr(arg)) { return true; }
643 }
644 return false;
645 }
646 case Expression::Kind::kConstructorArray:
647 case Expression::Kind::kConstructorArrayCast:
648 case Expression::Kind::kConstructorCompound:
649 case Expression::Kind::kConstructorCompoundCast:
650 case Expression::Kind::kConstructorDiagonalMatrix:
651 case Expression::Kind::kConstructorMatrixResize:
652 case Expression::Kind::kConstructorScalarCast:
653 case Expression::Kind::kConstructorSplat:
654 case Expression::Kind::kConstructorStruct: {
655 auto& c = e.asAnyConstructor();
656 for (auto& arg : c.argumentSpan()) {
657 if (this->visitExpressionPtr(arg)) { return true; }
658 }
659 return false;
660 }
661 case Expression::Kind::kExternalFunctionCall: {
662 auto& c = e.template as<ExternalFunctionCall>();
663 for (auto& arg : c.arguments()) {
664 if (this->visitExpressionPtr(arg)) { return true; }
665 }
666 return false;
667 }
668 case Expression::Kind::kFieldAccess:
669 return this->visitExpressionPtr(e.template as<FieldAccess>().base());
670
671 case Expression::Kind::kFunctionCall: {
672 auto& c = e.template as<FunctionCall>();
673 for (auto& arg : c.arguments()) {
674 if (arg && this->visitExpressionPtr(arg)) { return true; }
675 }
676 return false;
677 }
678 case Expression::Kind::kIndex: {
679 auto& i = e.template as<IndexExpression>();
680 return this->visitExpressionPtr(i.base()) || this->visitExpressionPtr(i.index());
681 }
682 case Expression::Kind::kPostfix:
683 return this->visitExpressionPtr(e.template as<PostfixExpression>().operand());
684
685 case Expression::Kind::kPrefix:
686 return this->visitExpressionPtr(e.template as<PrefixExpression>().operand());
687
688 case Expression::Kind::kSwizzle: {
689 auto& s = e.template as<Swizzle>();
690 return s.base() && this->visitExpressionPtr(s.base());
691 }
692
693 case Expression::Kind::kTernary: {
694 auto& t = e.template as<TernaryExpression>();
695 return this->visitExpressionPtr(t.test()) ||
696 (t.ifTrue() && this->visitExpressionPtr(t.ifTrue())) ||
697 (t.ifFalse() && this->visitExpressionPtr(t.ifFalse()));
698 }
699 default:
700 SkUNREACHABLE;
701 }
702 }
703
visitStatement(typename T::Statement & s)704 template <typename T> bool TProgramVisitor<T>::visitStatement(typename T::Statement& s) {
705 switch (s.kind()) {
706 case Statement::Kind::kBreak:
707 case Statement::Kind::kContinue:
708 case Statement::Kind::kDiscard:
709 case Statement::Kind::kInlineMarker:
710 case Statement::Kind::kNop:
711 // Leaf statements just return false
712 return false;
713
714 case Statement::Kind::kBlock:
715 for (auto& stmt : s.template as<Block>().children()) {
716 if (stmt && this->visitStatementPtr(stmt)) {
717 return true;
718 }
719 }
720 return false;
721
722 case Statement::Kind::kSwitchCase: {
723 auto& sc = s.template as<SwitchCase>();
724 if (sc.value() && this->visitExpressionPtr(sc.value())) {
725 return true;
726 }
727 return this->visitStatementPtr(sc.statement());
728 }
729 case Statement::Kind::kDo: {
730 auto& d = s.template as<DoStatement>();
731 return this->visitExpressionPtr(d.test()) || this->visitStatementPtr(d.statement());
732 }
733 case Statement::Kind::kExpression:
734 return this->visitExpressionPtr(s.template as<ExpressionStatement>().expression());
735
736 case Statement::Kind::kFor: {
737 auto& f = s.template as<ForStatement>();
738 return (f.initializer() && this->visitStatementPtr(f.initializer())) ||
739 (f.test() && this->visitExpressionPtr(f.test())) ||
740 (f.next() && this->visitExpressionPtr(f.next())) ||
741 this->visitStatementPtr(f.statement());
742 }
743 case Statement::Kind::kIf: {
744 auto& i = s.template as<IfStatement>();
745 return (i.test() && this->visitExpressionPtr(i.test())) ||
746 (i.ifTrue() && this->visitStatementPtr(i.ifTrue())) ||
747 (i.ifFalse() && this->visitStatementPtr(i.ifFalse()));
748 }
749 case Statement::Kind::kReturn: {
750 auto& r = s.template as<ReturnStatement>();
751 return r.expression() && this->visitExpressionPtr(r.expression());
752 }
753 case Statement::Kind::kSwitch: {
754 auto& sw = s.template as<SwitchStatement>();
755 if (this->visitExpressionPtr(sw.value())) {
756 return true;
757 }
758 for (auto& c : sw.cases()) {
759 if (this->visitStatementPtr(c)) {
760 return true;
761 }
762 }
763 return false;
764 }
765 case Statement::Kind::kVarDeclaration: {
766 auto& v = s.template as<VarDeclaration>();
767 return v.value() && this->visitExpressionPtr(v.value());
768 }
769 default:
770 SkUNREACHABLE;
771 }
772 }
773
visitProgramElement(typename T::ProgramElement & pe)774 template <typename T> bool TProgramVisitor<T>::visitProgramElement(typename T::ProgramElement& pe) {
775 switch (pe.kind()) {
776 case ProgramElement::Kind::kExtension:
777 case ProgramElement::Kind::kFunctionPrototype:
778 case ProgramElement::Kind::kInterfaceBlock:
779 case ProgramElement::Kind::kModifiers:
780 case ProgramElement::Kind::kStructDefinition:
781 // Leaf program elements just return false by default
782 return false;
783
784 case ProgramElement::Kind::kFunction:
785 return this->visitStatementPtr(pe.template as<FunctionDefinition>().body());
786
787 case ProgramElement::Kind::kGlobalVar:
788 return this->visitStatementPtr(pe.template as<GlobalVarDeclaration>().declaration());
789
790 default:
791 SkUNREACHABLE;
792 }
793 }
794
795 template class TProgramVisitor<ProgramVisitorTypes>;
796 template class TProgramVisitor<ProgramWriterTypes>;
797
798 } // namespace SkSL
799