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 if (pe.kind() == ProgramElement::Kind::kGlobalVar) {
535 const VarDeclaration& decl =
536 pe.as<GlobalVarDeclaration>().declaration()->as<VarDeclaration>();
537
538 size_t prevSlotsUsed = fGlobalSlotsUsed;
539 fGlobalSlotsUsed = SkSafeMath::Add(fGlobalSlotsUsed, decl.var().type().slotCount());
540 // To avoid overzealous error reporting, only trigger the error at the first
541 // place where the global limit is exceeded.
542 if (prevSlotsUsed < kVariableSlotLimit && fGlobalSlotsUsed >= kVariableSlotLimit) {
543 fContext.fErrors->error(pe.fLine, "global variable '" + decl.var().name() +
544 "' exceeds the size limit");
545 }
546 }
547 return INHERITED::visitProgramElement(pe);
548 }
549
550 bool visitStatement(const Statement& stmt) override {
551 if (!fContext.fConfig->fSettings.fPermitInvalidStaticTests) {
552 switch (stmt.kind()) {
553 case Statement::Kind::kIf:
554 if (stmt.as<IfStatement>().isStatic()) {
555 fContext.fErrors->error(stmt.fLine, "static if has non-static test");
556 }
557 break;
558
559 case Statement::Kind::kSwitch:
560 if (stmt.as<SwitchStatement>().isStatic()) {
561 fContext.fErrors->error(stmt.fLine,
562 "static switch has non-static test");
563 }
564 break;
565
566 default:
567 break;
568 }
569 }
570 return INHERITED::visitStatement(stmt);
571 }
572
573 bool visitExpression(const Expression& expr) override {
574 switch (expr.kind()) {
575 case Expression::Kind::kFunctionCall: {
576 const FunctionDeclaration& decl = expr.as<FunctionCall>().function();
577 if (!decl.isBuiltin() && !decl.definition()) {
578 fContext.fErrors->error(expr.fLine, "function '" + decl.description() +
579 "' is not defined");
580 }
581 break;
582 }
583 case Expression::Kind::kExternalFunctionReference:
584 case Expression::Kind::kFunctionReference:
585 case Expression::Kind::kMethodReference:
586 case Expression::Kind::kTypeReference:
587 SkDEBUGFAIL("invalid reference-expr, should have been reported by coerce()");
588 fContext.fErrors->error(expr.fLine, "invalid expression");
589 break;
590 default:
591 if (expr.type() == *fContext.fTypes.fInvalid) {
592 fContext.fErrors->error(expr.fLine, "invalid expression");
593 }
594 break;
595 }
596 return INHERITED::visitExpression(expr);
597 }
598
599 private:
600 using INHERITED = ProgramVisitor;
601 size_t fGlobalSlotsUsed = 0;
602 const Context& fContext;
603 };
604
605 // Check all of the program's owned elements. (Built-in elements are assumed to be valid.)
606 TestsAndExpressions visitor{*program.fContext};
607 for (const std::unique_ptr<ProgramElement>& element : program.fOwnedElements) {
608 visitor.visitProgramElement(*element);
609 }
610 }
611
612 ////////////////////////////////////////////////////////////////////////////////
613 // ProgramVisitor
614
visit(const Program & program)615 bool ProgramVisitor::visit(const Program& program) {
616 for (const ProgramElement* pe : program.elements()) {
617 if (this->visitProgramElement(*pe)) {
618 return true;
619 }
620 }
621 return false;
622 }
623
visitExpression(typename T::Expression & e)624 template <typename T> bool TProgramVisitor<T>::visitExpression(typename T::Expression& e) {
625 switch (e.kind()) {
626 case Expression::Kind::kCodeString:
627 case Expression::Kind::kExternalFunctionReference:
628 case Expression::Kind::kFunctionReference:
629 case Expression::Kind::kLiteral:
630 case Expression::Kind::kMethodReference:
631 case Expression::Kind::kPoison:
632 case Expression::Kind::kSetting:
633 case Expression::Kind::kTypeReference:
634 case Expression::Kind::kVariableReference:
635 // Leaf expressions return false
636 return false;
637
638 case Expression::Kind::kBinary: {
639 auto& b = e.template as<BinaryExpression>();
640 return (b.left() && this->visitExpressionPtr(b.left())) ||
641 (b.right() && this->visitExpressionPtr(b.right()));
642 }
643 case Expression::Kind::kChildCall: {
644 // We don't visit the child variable itself, just the arguments
645 auto& c = e.template as<ChildCall>();
646 for (auto& arg : c.arguments()) {
647 if (arg && this->visitExpressionPtr(arg)) { return true; }
648 }
649 return false;
650 }
651 case Expression::Kind::kConstructorArray:
652 case Expression::Kind::kConstructorArrayCast:
653 case Expression::Kind::kConstructorCompound:
654 case Expression::Kind::kConstructorCompoundCast:
655 case Expression::Kind::kConstructorDiagonalMatrix:
656 case Expression::Kind::kConstructorMatrixResize:
657 case Expression::Kind::kConstructorScalarCast:
658 case Expression::Kind::kConstructorSplat:
659 case Expression::Kind::kConstructorStruct: {
660 auto& c = e.asAnyConstructor();
661 for (auto& arg : c.argumentSpan()) {
662 if (this->visitExpressionPtr(arg)) { return true; }
663 }
664 return false;
665 }
666 case Expression::Kind::kExternalFunctionCall: {
667 auto& c = e.template as<ExternalFunctionCall>();
668 for (auto& arg : c.arguments()) {
669 if (this->visitExpressionPtr(arg)) { return true; }
670 }
671 return false;
672 }
673 case Expression::Kind::kFieldAccess:
674 return this->visitExpressionPtr(e.template as<FieldAccess>().base());
675
676 case Expression::Kind::kFunctionCall: {
677 auto& c = e.template as<FunctionCall>();
678 for (auto& arg : c.arguments()) {
679 if (arg && this->visitExpressionPtr(arg)) { return true; }
680 }
681 return false;
682 }
683 case Expression::Kind::kIndex: {
684 auto& i = e.template as<IndexExpression>();
685 return this->visitExpressionPtr(i.base()) || this->visitExpressionPtr(i.index());
686 }
687 case Expression::Kind::kPostfix:
688 return this->visitExpressionPtr(e.template as<PostfixExpression>().operand());
689
690 case Expression::Kind::kPrefix:
691 return this->visitExpressionPtr(e.template as<PrefixExpression>().operand());
692
693 case Expression::Kind::kSwizzle: {
694 auto& s = e.template as<Swizzle>();
695 return s.base() && this->visitExpressionPtr(s.base());
696 }
697
698 case Expression::Kind::kTernary: {
699 auto& t = e.template as<TernaryExpression>();
700 return this->visitExpressionPtr(t.test()) ||
701 (t.ifTrue() && this->visitExpressionPtr(t.ifTrue())) ||
702 (t.ifFalse() && this->visitExpressionPtr(t.ifFalse()));
703 }
704 default:
705 SkUNREACHABLE;
706 }
707 }
708
visitStatement(typename T::Statement & s)709 template <typename T> bool TProgramVisitor<T>::visitStatement(typename T::Statement& s) {
710 switch (s.kind()) {
711 case Statement::Kind::kBreak:
712 case Statement::Kind::kContinue:
713 case Statement::Kind::kDiscard:
714 case Statement::Kind::kInlineMarker:
715 case Statement::Kind::kNop:
716 // Leaf statements just return false
717 return false;
718
719 case Statement::Kind::kBlock:
720 for (auto& stmt : s.template as<Block>().children()) {
721 if (stmt && this->visitStatementPtr(stmt)) {
722 return true;
723 }
724 }
725 return false;
726
727 case Statement::Kind::kSwitchCase: {
728 auto& sc = s.template as<SwitchCase>();
729 if (sc.value() && this->visitExpressionPtr(sc.value())) {
730 return true;
731 }
732 return this->visitStatementPtr(sc.statement());
733 }
734 case Statement::Kind::kDo: {
735 auto& d = s.template as<DoStatement>();
736 return this->visitExpressionPtr(d.test()) || this->visitStatementPtr(d.statement());
737 }
738 case Statement::Kind::kExpression:
739 return this->visitExpressionPtr(s.template as<ExpressionStatement>().expression());
740
741 case Statement::Kind::kFor: {
742 auto& f = s.template as<ForStatement>();
743 return (f.initializer() && this->visitStatementPtr(f.initializer())) ||
744 (f.test() && this->visitExpressionPtr(f.test())) ||
745 (f.next() && this->visitExpressionPtr(f.next())) ||
746 this->visitStatementPtr(f.statement());
747 }
748 case Statement::Kind::kIf: {
749 auto& i = s.template as<IfStatement>();
750 return (i.test() && this->visitExpressionPtr(i.test())) ||
751 (i.ifTrue() && this->visitStatementPtr(i.ifTrue())) ||
752 (i.ifFalse() && this->visitStatementPtr(i.ifFalse()));
753 }
754 case Statement::Kind::kReturn: {
755 auto& r = s.template as<ReturnStatement>();
756 return r.expression() && this->visitExpressionPtr(r.expression());
757 }
758 case Statement::Kind::kSwitch: {
759 auto& sw = s.template as<SwitchStatement>();
760 if (this->visitExpressionPtr(sw.value())) {
761 return true;
762 }
763 for (auto& c : sw.cases()) {
764 if (this->visitStatementPtr(c)) {
765 return true;
766 }
767 }
768 return false;
769 }
770 case Statement::Kind::kVarDeclaration: {
771 auto& v = s.template as<VarDeclaration>();
772 return v.value() && this->visitExpressionPtr(v.value());
773 }
774 default:
775 SkUNREACHABLE;
776 }
777 }
778
visitProgramElement(typename T::ProgramElement & pe)779 template <typename T> bool TProgramVisitor<T>::visitProgramElement(typename T::ProgramElement& pe) {
780 switch (pe.kind()) {
781 case ProgramElement::Kind::kExtension:
782 case ProgramElement::Kind::kFunctionPrototype:
783 case ProgramElement::Kind::kInterfaceBlock:
784 case ProgramElement::Kind::kModifiers:
785 case ProgramElement::Kind::kStructDefinition:
786 // Leaf program elements just return false by default
787 return false;
788
789 case ProgramElement::Kind::kFunction:
790 return this->visitStatementPtr(pe.template as<FunctionDefinition>().body());
791
792 case ProgramElement::Kind::kGlobalVar:
793 return this->visitStatementPtr(pe.template as<GlobalVarDeclaration>().declaration());
794
795 default:
796 SkUNREACHABLE;
797 }
798 }
799
800 template class TProgramVisitor<ProgramVisitorTypes>;
801 template class TProgramVisitor<ProgramWriterTypes>;
802
803 } // namespace SkSL
804