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