1*c8dee2aaSAndroid Build Coastguard Worker /* 2*c8dee2aaSAndroid Build Coastguard Worker * Copyright 2021 Google LLC 3*c8dee2aaSAndroid Build Coastguard Worker * 4*c8dee2aaSAndroid Build Coastguard Worker * Use of this source code is governed by a BSD-style license that can be 5*c8dee2aaSAndroid Build Coastguard Worker * found in the LICENSE file. 6*c8dee2aaSAndroid Build Coastguard Worker */ 7*c8dee2aaSAndroid Build Coastguard Worker 8*c8dee2aaSAndroid Build Coastguard Worker #include "src/sksl/SkSLAnalysis.h" 9*c8dee2aaSAndroid Build Coastguard Worker 10*c8dee2aaSAndroid Build Coastguard Worker #include "src/sksl/analysis/SkSLProgramVisitor.h" 11*c8dee2aaSAndroid Build Coastguard Worker #include "src/sksl/ir/SkSLIRNode.h" 12*c8dee2aaSAndroid Build Coastguard Worker #include "src/sksl/ir/SkSLStatement.h" 13*c8dee2aaSAndroid Build Coastguard Worker 14*c8dee2aaSAndroid Build Coastguard Worker namespace SkSL { 15*c8dee2aaSAndroid Build Coastguard Worker 16*c8dee2aaSAndroid Build Coastguard Worker class Expression; 17*c8dee2aaSAndroid Build Coastguard Worker 18*c8dee2aaSAndroid Build Coastguard Worker namespace { 19*c8dee2aaSAndroid Build Coastguard Worker 20*c8dee2aaSAndroid Build Coastguard Worker class SwitchCaseContainsExit : public ProgramVisitor { 21*c8dee2aaSAndroid Build Coastguard Worker public: SwitchCaseContainsExit(bool conditionalExits)22*c8dee2aaSAndroid Build Coastguard Worker SwitchCaseContainsExit(bool conditionalExits) : fConditionalExits(conditionalExits) {} 23*c8dee2aaSAndroid Build Coastguard Worker visitExpression(const Expression & expr)24*c8dee2aaSAndroid Build Coastguard Worker bool visitExpression(const Expression& expr) override { 25*c8dee2aaSAndroid Build Coastguard Worker // We can avoid processing expressions entirely. 26*c8dee2aaSAndroid Build Coastguard Worker return false; 27*c8dee2aaSAndroid Build Coastguard Worker } 28*c8dee2aaSAndroid Build Coastguard Worker visitStatement(const Statement & stmt)29*c8dee2aaSAndroid Build Coastguard Worker bool visitStatement(const Statement& stmt) override { 30*c8dee2aaSAndroid Build Coastguard Worker switch (stmt.kind()) { 31*c8dee2aaSAndroid Build Coastguard Worker case Statement::Kind::kBlock: 32*c8dee2aaSAndroid Build Coastguard Worker case Statement::Kind::kSwitchCase: 33*c8dee2aaSAndroid Build Coastguard Worker return INHERITED::visitStatement(stmt); 34*c8dee2aaSAndroid Build Coastguard Worker 35*c8dee2aaSAndroid Build Coastguard Worker case Statement::Kind::kReturn: 36*c8dee2aaSAndroid Build Coastguard Worker // Returns are an early exit regardless of the surrounding control structures. 37*c8dee2aaSAndroid Build Coastguard Worker return fConditionalExits ? fInConditional : !fInConditional; 38*c8dee2aaSAndroid Build Coastguard Worker 39*c8dee2aaSAndroid Build Coastguard Worker case Statement::Kind::kContinue: 40*c8dee2aaSAndroid Build Coastguard Worker // Continues are an early exit from switches, but not loops. 41*c8dee2aaSAndroid Build Coastguard Worker return !fInLoop && 42*c8dee2aaSAndroid Build Coastguard Worker (fConditionalExits ? fInConditional : !fInConditional); 43*c8dee2aaSAndroid Build Coastguard Worker 44*c8dee2aaSAndroid Build Coastguard Worker case Statement::Kind::kBreak: 45*c8dee2aaSAndroid Build Coastguard Worker // Breaks cannot escape from switches or loops. 46*c8dee2aaSAndroid Build Coastguard Worker return !fInLoop && !fInSwitch && 47*c8dee2aaSAndroid Build Coastguard Worker (fConditionalExits ? fInConditional : !fInConditional); 48*c8dee2aaSAndroid Build Coastguard Worker 49*c8dee2aaSAndroid Build Coastguard Worker case Statement::Kind::kIf: { 50*c8dee2aaSAndroid Build Coastguard Worker ++fInConditional; 51*c8dee2aaSAndroid Build Coastguard Worker bool result = INHERITED::visitStatement(stmt); 52*c8dee2aaSAndroid Build Coastguard Worker --fInConditional; 53*c8dee2aaSAndroid Build Coastguard Worker return result; 54*c8dee2aaSAndroid Build Coastguard Worker } 55*c8dee2aaSAndroid Build Coastguard Worker 56*c8dee2aaSAndroid Build Coastguard Worker case Statement::Kind::kFor: 57*c8dee2aaSAndroid Build Coastguard Worker case Statement::Kind::kDo: { 58*c8dee2aaSAndroid Build Coastguard Worker // Loops are treated as conditionals because a loop could potentially execute zero 59*c8dee2aaSAndroid Build Coastguard Worker // times. We don't have a straightforward way to determine that a loop definitely 60*c8dee2aaSAndroid Build Coastguard Worker // executes at least once. 61*c8dee2aaSAndroid Build Coastguard Worker ++fInConditional; 62*c8dee2aaSAndroid Build Coastguard Worker ++fInLoop; 63*c8dee2aaSAndroid Build Coastguard Worker bool result = INHERITED::visitStatement(stmt); 64*c8dee2aaSAndroid Build Coastguard Worker --fInLoop; 65*c8dee2aaSAndroid Build Coastguard Worker --fInConditional; 66*c8dee2aaSAndroid Build Coastguard Worker return result; 67*c8dee2aaSAndroid Build Coastguard Worker } 68*c8dee2aaSAndroid Build Coastguard Worker 69*c8dee2aaSAndroid Build Coastguard Worker case Statement::Kind::kSwitch: { 70*c8dee2aaSAndroid Build Coastguard Worker ++fInSwitch; 71*c8dee2aaSAndroid Build Coastguard Worker bool result = INHERITED::visitStatement(stmt); 72*c8dee2aaSAndroid Build Coastguard Worker --fInSwitch; 73*c8dee2aaSAndroid Build Coastguard Worker return result; 74*c8dee2aaSAndroid Build Coastguard Worker } 75*c8dee2aaSAndroid Build Coastguard Worker 76*c8dee2aaSAndroid Build Coastguard Worker default: 77*c8dee2aaSAndroid Build Coastguard Worker return false; 78*c8dee2aaSAndroid Build Coastguard Worker } 79*c8dee2aaSAndroid Build Coastguard Worker } 80*c8dee2aaSAndroid Build Coastguard Worker 81*c8dee2aaSAndroid Build Coastguard Worker bool fConditionalExits = false; 82*c8dee2aaSAndroid Build Coastguard Worker int fInConditional = 0; 83*c8dee2aaSAndroid Build Coastguard Worker int fInLoop = 0; 84*c8dee2aaSAndroid Build Coastguard Worker int fInSwitch = 0; 85*c8dee2aaSAndroid Build Coastguard Worker using INHERITED = ProgramVisitor; 86*c8dee2aaSAndroid Build Coastguard Worker }; 87*c8dee2aaSAndroid Build Coastguard Worker 88*c8dee2aaSAndroid Build Coastguard Worker } // namespace 89*c8dee2aaSAndroid Build Coastguard Worker SwitchCaseContainsUnconditionalExit(const Statement & stmt)90*c8dee2aaSAndroid Build Coastguard Workerbool Analysis::SwitchCaseContainsUnconditionalExit(const Statement& stmt) { 91*c8dee2aaSAndroid Build Coastguard Worker return SwitchCaseContainsExit{/*conditionalExits=*/false}.visitStatement(stmt); 92*c8dee2aaSAndroid Build Coastguard Worker } 93*c8dee2aaSAndroid Build Coastguard Worker SwitchCaseContainsConditionalExit(const Statement & stmt)94*c8dee2aaSAndroid Build Coastguard Workerbool Analysis::SwitchCaseContainsConditionalExit(const Statement& stmt) { 95*c8dee2aaSAndroid Build Coastguard Worker return SwitchCaseContainsExit{/*conditionalExits=*/true}.visitStatement(stmt); 96*c8dee2aaSAndroid Build Coastguard Worker } 97*c8dee2aaSAndroid Build Coastguard Worker 98*c8dee2aaSAndroid Build Coastguard Worker } // namespace SkSL 99