• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2016 Google Inc.
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 #ifndef SKSL_CFGGENERATOR
9 #define SKSL_CFGGENERATOR
10 
11 #include "src/sksl/ir/SkSLExpression.h"
12 #include "src/sksl/ir/SkSLFunctionDefinition.h"
13 
14 #include <set>
15 #include <stack>
16 
17 namespace SkSL {
18 
19 // index of a block within CFG.fBlocks
20 typedef size_t BlockId;
21 
22 struct BasicBlock {
23     struct Node {
24         enum Kind {
25             kStatement_Kind,
26             kExpression_Kind
27         };
28 
NodeBasicBlock::Node29         Node(Kind kind, bool constantPropagation, std::unique_ptr<Expression>* expression,
30              std::unique_ptr<Statement>* statement)
31         : fKind(kind)
32         , fConstantPropagation(constantPropagation)
33         , fExpression(expression)
34         , fStatement(statement) {}
35 
expressionBasicBlock::Node36         std::unique_ptr<Expression>* expression() const {
37             SkASSERT(fKind == kExpression_Kind);
38             return fExpression;
39         }
40 
setExpressionBasicBlock::Node41         void setExpression(std::unique_ptr<Expression> expr) {
42             SkASSERT(fKind == kExpression_Kind);
43             *fExpression = std::move(expr);
44         }
45 
statementBasicBlock::Node46         std::unique_ptr<Statement>* statement() const {
47             SkASSERT(fKind == kStatement_Kind);
48             return fStatement;
49         }
50 
setStatementBasicBlock::Node51         void setStatement(std::unique_ptr<Statement> stmt) {
52             SkASSERT(fKind == kStatement_Kind);
53             *fStatement = std::move(stmt);
54         }
55 
56 #ifdef SK_DEBUG
descriptionBasicBlock::Node57         String description() const {
58             if (fKind == kStatement_Kind) {
59                 return (*fStatement)->description();
60             } else {
61                 SkASSERT(fKind == kExpression_Kind);
62                 return (*fExpression)->description();
63             }
64         }
65 #endif
66 
67         Kind fKind;
68         // if false, this node should not be subject to constant propagation. This happens with
69         // compound assignment (i.e. x *= 2), in which the value x is used as an rvalue for
70         // multiplication by 2 and then as an lvalue for assignment purposes. Since there is only
71         // one "x" node, replacing it with a constant would break the assignment and we suppress
72         // it. Down the road, we should handle this more elegantly by substituting a regular
73         // assignment if the target is constant (i.e. x = 1; x *= 2; should become x = 1; x = 1 * 2;
74         // and then collapse down to a simple x = 2;).
75         bool fConstantPropagation;
76 
77     private:
78         // we store pointers to the unique_ptrs so that we can replace expressions or statements
79         // during optimization without having to regenerate the entire tree
80         std::unique_ptr<Expression>* fExpression;
81         std::unique_ptr<Statement>* fStatement;
82     };
83 
84     /**
85      * Attempts to remove the expression (and its subexpressions) pointed to by the iterator. If the
86      * expression can be cleanly removed, returns true and updates the iterator to point to the
87      * expression after the deleted expression. Otherwise returns false (and the CFG will need to be
88      * regenerated).
89      */
90     bool tryRemoveExpression(std::vector<BasicBlock::Node>::iterator* iter);
91 
92     /**
93      * Locates and attempts remove an expression occurring before the expression pointed to by iter.
94      * If the expression can be cleanly removed, returns true and resets iter to a valid iterator
95      * pointing to the same expression it did initially. Otherwise returns false (and the CFG will
96      * need to be regenerated).
97      */
98     bool tryRemoveExpressionBefore(std::vector<BasicBlock::Node>::iterator* iter, Expression* e);
99 
100     /**
101      * As tryRemoveExpressionBefore, but for lvalues. As lvalues are at most partially evaluated
102      * (for instance, x[i] = 0 evaluates i but not x) this will only look for the parts of the
103      * lvalue that are actually evaluated.
104      */
105     bool tryRemoveLValueBefore(std::vector<BasicBlock::Node>::iterator* iter, Expression* lvalue);
106 
107     /**
108      * Attempts to inserts a new expression before the node pointed to by iter. If the
109      * expression can be cleanly inserted, returns true and updates the iterator to point to the
110      * newly inserted expression. Otherwise returns false (and the CFG will need to be regenerated).
111      */
112     bool tryInsertExpression(std::vector<BasicBlock::Node>::iterator* iter,
113                              std::unique_ptr<Expression>* expr);
114 
115     std::vector<Node> fNodes;
116     std::set<BlockId> fEntrances;
117     std::set<BlockId> fExits;
118     // variable definitions upon entering this basic block (null expression = undefined)
119     DefinitionMap fBefore;
120 };
121 
122 struct CFG {
123     BlockId fStart;
124     BlockId fExit;
125     std::vector<BasicBlock> fBlocks;
126 
127     void dump();
128 
129 private:
130     BlockId fCurrent;
131 
132     // Adds a new block, adds an exit* from the current block to the new block, then marks the new
133     // block as the current block
134     // *see note in addExit()
135     BlockId newBlock();
136 
137     // Adds a new block, but does not mark it current or add an exit from the current block
138     BlockId newIsolatedBlock();
139 
140     // Adds an exit from the 'from' block to the 'to' block
141     // Note that we skip adding the exit if the 'from' block is itself unreachable; this means that
142     // we don't actually have to trace the tree to see if a particular block is unreachable, we can
143     // just check to see if it has any entrances. This does require a bit of care in the order in
144     // which we set the CFG up.
145     void addExit(BlockId from, BlockId to);
146 
147     friend class CFGGenerator;
148 };
149 
150 /**
151  * Converts functions into control flow graphs.
152  */
153 class CFGGenerator {
154 public:
CFGGenerator()155     CFGGenerator() {}
156 
157     CFG getCFG(FunctionDefinition& f);
158 
159 private:
160     void addStatement(CFG& cfg, std::unique_ptr<Statement>* s);
161 
162     void addExpression(CFG& cfg, std::unique_ptr<Expression>* e, bool constantPropagate);
163 
164     void addLValue(CFG& cfg, std::unique_ptr<Expression>* e);
165 
166     std::stack<BlockId> fLoopContinues;
167     std::stack<BlockId> fLoopExits;
168 };
169 
170 }
171 
172 #endif
173