xref: /aosp_15_r20/external/skia/src/sksl/analysis/SkSLGetLoopControlFlowInfo.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1 /*
2  * Copyright 2023 Google LLC
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "src/sksl/SkSLAnalysis.h"
9 
10 #include "src/sksl/analysis/SkSLProgramVisitor.h"
11 #include "src/sksl/ir/SkSLIRNode.h"
12 #include "src/sksl/ir/SkSLStatement.h"
13 
14 namespace SkSL {
15 
16 class Expression;
17 
18 namespace Analysis {
19 namespace {
20 
21 class LoopControlFlowVisitor : public ProgramVisitor {
22 public:
LoopControlFlowVisitor()23     LoopControlFlowVisitor() {}
24 
visitExpression(const Expression & expr)25     bool visitExpression(const Expression& expr) override {
26         // We can avoid processing expressions entirely.
27         return false;
28     }
29 
visitStatement(const Statement & stmt)30     bool visitStatement(const Statement& stmt) override {
31         switch (stmt.kind()) {
32             case Statement::Kind::kContinue:
33                 // A continue only affects the control flow of the loop if it's not nested inside
34                 // another looping structure. (Inside a switch, SkSL disallows continue entirely.)
35                 fResult.fHasContinue |= (fDepth == 0);
36                 break;
37 
38             case Statement::Kind::kBreak:
39                 // A break only affects the control flow of the loop if it's not nested inside
40                 // another loop/switch structure.
41                 fResult.fHasBreak |= (fDepth == 0);
42                 break;
43 
44             case Statement::Kind::kReturn:
45                 // A return will abort the loop's control flow no matter how deeply it is nested.
46                 fResult.fHasReturn = true;
47                 break;
48 
49             case Statement::Kind::kFor:
50             case Statement::Kind::kDo:
51             case Statement::Kind::kSwitch: {
52                 ++fDepth;
53                 bool done = ProgramVisitor::visitStatement(stmt);
54                 --fDepth;
55                 return done;
56             }
57 
58             default:
59                 return ProgramVisitor::visitStatement(stmt);
60         }
61 
62         // If we've already found everything we're hunting for, we can stop searching early.
63         return fResult.fHasContinue && fResult.fHasBreak && fResult.fHasReturn;
64     }
65 
66     LoopControlFlowInfo fResult;
67     int fDepth = 0;
68 };
69 
70 }  // namespace
71 
GetLoopControlFlowInfo(const Statement & stmt)72 LoopControlFlowInfo GetLoopControlFlowInfo(const Statement& stmt) {
73     LoopControlFlowVisitor visitor;
74     visitor.visitStatement(stmt);
75     return visitor.fResult;
76 }
77 
78 }  // namespace Analysis
79 }  // namespace SkSL
80