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