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
319 // If AF is enabled, force to use PassThrough mode
320 if (program.fConfig != nullptr && program.fConfig->fSettings.fUseAF) {
321 result.setKind(SampleUsage::Kind::kPassThrough);
322 }
323 return result;
324 }
325
ReferencesBuiltin(const Program & program,int builtin)326 bool Analysis::ReferencesBuiltin(const Program& program, int builtin) {
327 BuiltinVariableVisitor visitor(builtin);
328 return visitor.visit(program);
329 }
330
ReferencesSampleCoords(const Program & program)331 bool Analysis::ReferencesSampleCoords(const Program& program) {
332 return Analysis::ReferencesBuiltin(program, SK_MAIN_COORDS_BUILTIN);
333 }
334
ReferencesFragCoords(const Program & program)335 bool Analysis::ReferencesFragCoords(const Program& program) {
336 return Analysis::ReferencesBuiltin(program, SK_FRAGCOORD_BUILTIN);
337 }
338
CallsSampleOutsideMain(const Program & program)339 bool Analysis::CallsSampleOutsideMain(const Program& program) {
340 SampleOutsideMainVisitor visitor;
341 return visitor.visit(program);
342 }
343
DetectVarDeclarationWithoutScope(const Statement & stmt,ErrorReporter * errors)344 bool Analysis::DetectVarDeclarationWithoutScope(const Statement& stmt, ErrorReporter* errors) {
345 // A variable declaration can create either a lone VarDeclaration or an unscoped Block
346 // containing multiple VarDeclaration statements. We need to detect either case.
347 const Variable* var;
348 if (stmt.is<VarDeclaration>()) {
349 // The single-variable case. No blocks at all.
350 var = &stmt.as<VarDeclaration>().var();
351 } else if (stmt.is<Block>()) {
352 // The multiple-variable case: an unscoped, non-empty block...
353 const Block& block = stmt.as<Block>();
354 if (block.isScope() || block.children().empty()) {
355 return false;
356 }
357 // ... holding a variable declaration.
358 const Statement& innerStmt = *block.children().front();
359 if (!innerStmt.is<VarDeclaration>()) {
360 return false;
361 }
362 var = &innerStmt.as<VarDeclaration>().var();
363 } else {
364 // This statement wasn't a variable declaration. No problem.
365 return false;
366 }
367
368 // Report an error.
369 SkASSERT(var);
370 if (errors) {
371 errors->error(stmt.fLine, "variable '" + var->name() + "' must be created in a scope");
372 }
373 return true;
374 }
375
NodeCountUpToLimit(const FunctionDefinition & function,int limit)376 int Analysis::NodeCountUpToLimit(const FunctionDefinition& function, int limit) {
377 return NodeCountVisitor{limit}.visit(*function.body());
378 }
379
StatementWritesToVariable(const Statement & stmt,const Variable & var)380 bool Analysis::StatementWritesToVariable(const Statement& stmt, const Variable& var) {
381 return VariableWriteVisitor(&var).visit(stmt);
382 }
383
IsAssignable(Expression & expr,AssignmentInfo * info,ErrorReporter * errors)384 bool Analysis::IsAssignable(Expression& expr, AssignmentInfo* info, ErrorReporter* errors) {
385 TrivialErrorReporter trivialErrors;
386 return IsAssignableVisitor{errors ? errors : &trivialErrors}.visit(expr, info);
387 }
388
UpdateVariableRefKind(Expression * expr,VariableReference::RefKind kind,ErrorReporter * errors)389 bool Analysis::UpdateVariableRefKind(Expression* expr,
390 VariableReference::RefKind kind,
391 ErrorReporter* errors) {
392 Analysis::AssignmentInfo info;
393 if (!Analysis::IsAssignable(*expr, &info, errors)) {
394 return false;
395 }
396 if (!info.fAssignedVar) {
397 if (errors) {
398 errors->error(expr->fLine, "can't assign to expression '" + expr->description() + "'");
399 }
400 return false;
401 }
402 info.fAssignedVar->setRefKind(kind);
403 return true;
404 }
405
IsTrivialExpression(const Expression & expr)406 bool Analysis::IsTrivialExpression(const Expression& expr) {
407 return expr.is<Literal>() ||
408 expr.is<VariableReference>() ||
409 (expr.is<Swizzle>() &&
410 IsTrivialExpression(*expr.as<Swizzle>().base())) ||
411 (expr.is<FieldAccess>() &&
412 IsTrivialExpression(*expr.as<FieldAccess>().base())) ||
413 (expr.isAnyConstructor() &&
414 expr.asAnyConstructor().argumentSpan().size() == 1 &&
415 IsTrivialExpression(*expr.asAnyConstructor().argumentSpan().front())) ||
416 (expr.isAnyConstructor() &&
417 expr.isConstantOrUniform()) ||
418 (expr.is<IndexExpression>() &&
419 expr.as<IndexExpression>().index()->isIntLiteral() &&
420 IsTrivialExpression(*expr.as<IndexExpression>().base()));
421 }
422
IsSameExpressionTree(const Expression & left,const Expression & right)423 bool Analysis::IsSameExpressionTree(const Expression& left, const Expression& right) {
424 if (left.kind() != right.kind() || left.type() != right.type()) {
425 return false;
426 }
427
428 // This isn't a fully exhaustive list of expressions by any stretch of the imagination; for
429 // instance, `x[y+1] = x[y+1]` isn't detected because we don't look at BinaryExpressions.
430 // Since this is intended to be used for optimization purposes, handling the common cases is
431 // sufficient.
432 switch (left.kind()) {
433 case Expression::Kind::kLiteral:
434 return left.as<Literal>().value() == right.as<Literal>().value();
435
436 case Expression::Kind::kConstructorArray:
437 case Expression::Kind::kConstructorArrayCast:
438 case Expression::Kind::kConstructorCompound:
439 case Expression::Kind::kConstructorCompoundCast:
440 case Expression::Kind::kConstructorDiagonalMatrix:
441 case Expression::Kind::kConstructorMatrixResize:
442 case Expression::Kind::kConstructorScalarCast:
443 case Expression::Kind::kConstructorStruct:
444 case Expression::Kind::kConstructorSplat: {
445 if (left.kind() != right.kind()) {
446 return false;
447 }
448 const AnyConstructor& leftCtor = left.asAnyConstructor();
449 const AnyConstructor& rightCtor = right.asAnyConstructor();
450 const auto leftSpan = leftCtor.argumentSpan();
451 const auto rightSpan = rightCtor.argumentSpan();
452 if (leftSpan.size() != rightSpan.size()) {
453 return false;
454 }
455 for (size_t index = 0; index < leftSpan.size(); ++index) {
456 if (!IsSameExpressionTree(*leftSpan[index], *rightSpan[index])) {
457 return false;
458 }
459 }
460 return true;
461 }
462 case Expression::Kind::kFieldAccess:
463 return left.as<FieldAccess>().fieldIndex() == right.as<FieldAccess>().fieldIndex() &&
464 IsSameExpressionTree(*left.as<FieldAccess>().base(),
465 *right.as<FieldAccess>().base());
466
467 case Expression::Kind::kIndex:
468 return IsSameExpressionTree(*left.as<IndexExpression>().index(),
469 *right.as<IndexExpression>().index()) &&
470 IsSameExpressionTree(*left.as<IndexExpression>().base(),
471 *right.as<IndexExpression>().base());
472
473 case Expression::Kind::kSwizzle:
474 return left.as<Swizzle>().components() == right.as<Swizzle>().components() &&
475 IsSameExpressionTree(*left.as<Swizzle>().base(), *right.as<Swizzle>().base());
476
477 case Expression::Kind::kVariableReference:
478 return left.as<VariableReference>().variable() ==
479 right.as<VariableReference>().variable();
480
481 default:
482 return false;
483 }
484 }
485
486 class ES2IndexingVisitor : public ProgramVisitor {
487 public:
ES2IndexingVisitor(ErrorReporter & errors)488 ES2IndexingVisitor(ErrorReporter& errors) : fErrors(errors) {}
489
visitStatement(const Statement & s)490 bool visitStatement(const Statement& s) override {
491 if (s.is<ForStatement>()) {
492 const ForStatement& f = s.as<ForStatement>();
493 SkASSERT(f.initializer() && f.initializer()->is<VarDeclaration>());
494 const Variable* var = &f.initializer()->as<VarDeclaration>().var();
495 auto [iter, inserted] = fLoopIndices.insert(var);
496 SkASSERT(inserted);
497 bool result = this->visitStatement(*f.statement());
498 fLoopIndices.erase(iter);
499 return result;
500 }
501 return INHERITED::visitStatement(s);
502 }
503
visitExpression(const Expression & e)504 bool visitExpression(const Expression& e) override {
505 if (e.is<IndexExpression>()) {
506 const IndexExpression& i = e.as<IndexExpression>();
507 if (!Analysis::IsConstantIndexExpression(*i.index(), &fLoopIndices)) {
508 fErrors.error(i.fLine, "index expression must be constant");
509 return true;
510 }
511 }
512 return INHERITED::visitExpression(e);
513 }
514
515 using ProgramVisitor::visitProgramElement;
516
517 private:
518 ErrorReporter& fErrors;
519 std::set<const Variable*> fLoopIndices;
520 using INHERITED = ProgramVisitor;
521 };
522
ValidateIndexingForES2(const ProgramElement & pe,ErrorReporter & errors)523 void Analysis::ValidateIndexingForES2(const ProgramElement& pe, ErrorReporter& errors) {
524 ES2IndexingVisitor visitor(errors);
525 visitor.visitProgramElement(pe);
526 }
527
VerifyStaticTestsAndExpressions(const Program & program)528 void Analysis::VerifyStaticTestsAndExpressions(const Program& program) {
529 class TestsAndExpressions : public ProgramVisitor {
530 public:
531 TestsAndExpressions(const Context& ctx) : fContext(ctx) {}
532
533 bool visitProgramElement(const ProgramElement& pe) override {
534 #ifndef SKSL_EXT
535 if (pe.kind() == ProgramElement::Kind::kGlobalVar) {
536 const VarDeclaration& decl =
537 pe.as<GlobalVarDeclaration>().declaration()->as<VarDeclaration>();
538
539 size_t prevSlotsUsed = fGlobalSlotsUsed;
540 fGlobalSlotsUsed = SkSafeMath::Add(fGlobalSlotsUsed, decl.var().type().slotCount());
541 // To avoid overzealous error reporting, only trigger the error at the first
542 // place where the global limit is exceeded.
543 if (prevSlotsUsed < kVariableSlotLimit && fGlobalSlotsUsed >= kVariableSlotLimit) {
544 fContext.fErrors->error(pe.fLine, "global variable '" + decl.var().name() +
545 "' exceeds the size limit");
546 }
547 }
548 #endif
549 return INHERITED::visitProgramElement(pe);
550 }
551
552 bool visitStatement(const Statement& stmt) override {
553 if (!fContext.fConfig->fSettings.fPermitInvalidStaticTests) {
554 switch (stmt.kind()) {
555 case Statement::Kind::kIf:
556 if (stmt.as<IfStatement>().isStatic()) {
557 fContext.fErrors->error(stmt.fLine, "static if has non-static test");
558 }
559 break;
560
561 case Statement::Kind::kSwitch:
562 if (stmt.as<SwitchStatement>().isStatic()) {
563 fContext.fErrors->error(stmt.fLine,
564 "static switch has non-static test");
565 }
566 break;
567
568 default:
569 break;
570 }
571 }
572 return INHERITED::visitStatement(stmt);
573 }
574
575 bool visitExpression(const Expression& expr) override {
576 switch (expr.kind()) {
577 case Expression::Kind::kFunctionCall: {
578 const FunctionDeclaration& decl = expr.as<FunctionCall>().function();
579 if (!decl.isBuiltin() && !decl.definition()) {
580 fContext.fErrors->error(expr.fLine, "function '" + decl.description() +
581 "' is not defined");
582 }
583 break;
584 }
585 case Expression::Kind::kExternalFunctionReference:
586 case Expression::Kind::kFunctionReference:
587 case Expression::Kind::kMethodReference:
588 case Expression::Kind::kTypeReference:
589 SkDEBUGFAIL("invalid reference-expr, should have been reported by coerce()");
590 fContext.fErrors->error(expr.fLine, "invalid expression");
591 break;
592 default:
593 if (expr.type() == *fContext.fTypes.fInvalid) {
594 fContext.fErrors->error(expr.fLine, "invalid expression");
595 }
596 break;
597 }
598 return INHERITED::visitExpression(expr);
599 }
600
601 private:
602 using INHERITED = ProgramVisitor;
603 size_t fGlobalSlotsUsed = 0;
604 const Context& fContext;
605 };
606
607 // Check all of the program's owned elements. (Built-in elements are assumed to be valid.)
608 TestsAndExpressions visitor{*program.fContext};
609 for (const std::unique_ptr<ProgramElement>& element : program.fOwnedElements) {
610 visitor.visitProgramElement(*element);
611 }
612 }
613
614 ////////////////////////////////////////////////////////////////////////////////
615 // ProgramVisitor
616
visit(const Program & program)617 bool ProgramVisitor::visit(const Program& program) {
618 for (const ProgramElement* pe : program.elements()) {
619 if (this->visitProgramElement(*pe)) {
620 return true;
621 }
622 }
623 return false;
624 }
625
visitExpression(typename T::Expression & e)626 template <typename T> bool TProgramVisitor<T>::visitExpression(typename T::Expression& e) {
627 switch (e.kind()) {
628 case Expression::Kind::kCodeString:
629 case Expression::Kind::kExternalFunctionReference:
630 case Expression::Kind::kFunctionReference:
631 case Expression::Kind::kLiteral:
632 case Expression::Kind::kMethodReference:
633 case Expression::Kind::kPoison:
634 case Expression::Kind::kSetting:
635 case Expression::Kind::kTypeReference:
636 case Expression::Kind::kVariableReference:
637 // Leaf expressions return false
638 return false;
639
640 case Expression::Kind::kBinary: {
641 auto& b = e.template as<BinaryExpression>();
642 return (b.left() && this->visitExpressionPtr(b.left())) ||
643 (b.right() && this->visitExpressionPtr(b.right()));
644 }
645 case Expression::Kind::kChildCall: {
646 // We don't visit the child variable itself, just the arguments
647 auto& c = e.template as<ChildCall>();
648 for (auto& arg : c.arguments()) {
649 if (arg && this->visitExpressionPtr(arg)) { return true; }
650 }
651 return false;
652 }
653 case Expression::Kind::kConstructorArray:
654 case Expression::Kind::kConstructorArrayCast:
655 case Expression::Kind::kConstructorCompound:
656 case Expression::Kind::kConstructorCompoundCast:
657 case Expression::Kind::kConstructorDiagonalMatrix:
658 case Expression::Kind::kConstructorMatrixResize:
659 case Expression::Kind::kConstructorScalarCast:
660 case Expression::Kind::kConstructorSplat:
661 case Expression::Kind::kConstructorStruct: {
662 auto& c = e.asAnyConstructor();
663 for (auto& arg : c.argumentSpan()) {
664 if (this->visitExpressionPtr(arg)) { return true; }
665 }
666 return false;
667 }
668 case Expression::Kind::kExternalFunctionCall: {
669 auto& c = e.template as<ExternalFunctionCall>();
670 for (auto& arg : c.arguments()) {
671 if (this->visitExpressionPtr(arg)) { return true; }
672 }
673 return false;
674 }
675 case Expression::Kind::kFieldAccess:
676 return this->visitExpressionPtr(e.template as<FieldAccess>().base());
677
678 case Expression::Kind::kFunctionCall: {
679 auto& c = e.template as<FunctionCall>();
680 for (auto& arg : c.arguments()) {
681 if (arg && this->visitExpressionPtr(arg)) { return true; }
682 }
683 return false;
684 }
685 case Expression::Kind::kIndex: {
686 auto& i = e.template as<IndexExpression>();
687 return this->visitExpressionPtr(i.base()) || this->visitExpressionPtr(i.index());
688 }
689 case Expression::Kind::kPostfix:
690 return this->visitExpressionPtr(e.template as<PostfixExpression>().operand());
691
692 case Expression::Kind::kPrefix:
693 return this->visitExpressionPtr(e.template as<PrefixExpression>().operand());
694
695 case Expression::Kind::kSwizzle: {
696 auto& s = e.template as<Swizzle>();
697 return s.base() && this->visitExpressionPtr(s.base());
698 }
699
700 case Expression::Kind::kTernary: {
701 auto& t = e.template as<TernaryExpression>();
702 return this->visitExpressionPtr(t.test()) ||
703 (t.ifTrue() && this->visitExpressionPtr(t.ifTrue())) ||
704 (t.ifFalse() && this->visitExpressionPtr(t.ifFalse()));
705 }
706 default:
707 SkUNREACHABLE;
708 }
709 }
710
visitStatement(typename T::Statement & s)711 template <typename T> bool TProgramVisitor<T>::visitStatement(typename T::Statement& s) {
712 switch (s.kind()) {
713 case Statement::Kind::kBreak:
714 case Statement::Kind::kContinue:
715 case Statement::Kind::kDiscard:
716 case Statement::Kind::kInlineMarker:
717 case Statement::Kind::kNop:
718 // Leaf statements just return false
719 return false;
720
721 case Statement::Kind::kBlock:
722 for (auto& stmt : s.template as<Block>().children()) {
723 if (stmt && this->visitStatementPtr(stmt)) {
724 return true;
725 }
726 }
727 return false;
728
729 case Statement::Kind::kSwitchCase: {
730 auto& sc = s.template as<SwitchCase>();
731 if (sc.value() && this->visitExpressionPtr(sc.value())) {
732 return true;
733 }
734 return this->visitStatementPtr(sc.statement());
735 }
736 case Statement::Kind::kDo: {
737 auto& d = s.template as<DoStatement>();
738 return this->visitExpressionPtr(d.test()) || this->visitStatementPtr(d.statement());
739 }
740 case Statement::Kind::kExpression:
741 return this->visitExpressionPtr(s.template as<ExpressionStatement>().expression());
742
743 case Statement::Kind::kFor: {
744 auto& f = s.template as<ForStatement>();
745 return (f.initializer() && this->visitStatementPtr(f.initializer())) ||
746 (f.test() && this->visitExpressionPtr(f.test())) ||
747 (f.next() && this->visitExpressionPtr(f.next())) ||
748 this->visitStatementPtr(f.statement());
749 }
750 case Statement::Kind::kIf: {
751 auto& i = s.template as<IfStatement>();
752 return (i.test() && this->visitExpressionPtr(i.test())) ||
753 (i.ifTrue() && this->visitStatementPtr(i.ifTrue())) ||
754 (i.ifFalse() && this->visitStatementPtr(i.ifFalse()));
755 }
756 case Statement::Kind::kReturn: {
757 auto& r = s.template as<ReturnStatement>();
758 return r.expression() && this->visitExpressionPtr(r.expression());
759 }
760 case Statement::Kind::kSwitch: {
761 auto& sw = s.template as<SwitchStatement>();
762 if (this->visitExpressionPtr(sw.value())) {
763 return true;
764 }
765 for (auto& c : sw.cases()) {
766 if (this->visitStatementPtr(c)) {
767 return true;
768 }
769 }
770 return false;
771 }
772 case Statement::Kind::kVarDeclaration: {
773 auto& v = s.template as<VarDeclaration>();
774 return v.value() && this->visitExpressionPtr(v.value());
775 }
776 default:
777 SkUNREACHABLE;
778 }
779 }
780
visitProgramElement(typename T::ProgramElement & pe)781 template <typename T> bool TProgramVisitor<T>::visitProgramElement(typename T::ProgramElement& pe) {
782 switch (pe.kind()) {
783 case ProgramElement::Kind::kExtension:
784 case ProgramElement::Kind::kFunctionPrototype:
785 case ProgramElement::Kind::kInterfaceBlock:
786 case ProgramElement::Kind::kModifiers:
787 case ProgramElement::Kind::kStructDefinition:
788 // Leaf program elements just return false by default
789 return false;
790
791 case ProgramElement::Kind::kFunction:
792 return this->visitStatementPtr(pe.template as<FunctionDefinition>().body());
793
794 case ProgramElement::Kind::kGlobalVar:
795 return this->visitStatementPtr(pe.template as<GlobalVarDeclaration>().declaration());
796
797 default:
798 SkUNREACHABLE;
799 }
800 }
801
802 template class TProgramVisitor<ProgramVisitorTypes>;
803 template class TProgramVisitor<ProgramWriterTypes>;
804
805 } // namespace SkSL
806