blob: 0a03d69fc625310e88d2564540a1e117cdb58edf [file] [log] [blame]
ethannicholas22f939e2016-10-13 13:25:34 -07001/*
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 */
Ethan Nicholas0df1b042017-03-31 13:56:23 -04007
ethannicholas22f939e2016-10-13 13:25:34 -07008#ifndef SKSL_CFGGENERATOR
9#define SKSL_CFGGENERATOR
10
11#include "ir/SkSLExpression.h"
12#include "ir/SkSLFunctionDefinition.h"
13
14#include <set>
15#include <stack>
16
17namespace SkSL {
18
19// index of a block within CFG.fBlocks
20typedef size_t BlockId;
21
22struct BasicBlock {
23 struct Node {
24 enum Kind {
25 kStatement_Kind,
26 kExpression_Kind
27 };
28
29 Kind fKind;
Ethan Nicholas86a43402017-01-19 13:32:00 -050030 // if false, this node should not be subject to constant propagation. This happens with
31 // compound assignment (i.e. x *= 2), in which the value x is used as an rvalue for
32 // multiplication by 2 and then as an lvalue for assignment purposes. Since there is only
33 // one "x" node, replacing it with a constant would break the assignment and we suppress
34 // it. Down the road, we should handle this more elegantly by substituting a regular
35 // assignment if the target is constant (i.e. x = 1; x *= 2; should become x = 1; x = 1 * 2;
36 // and then collapse down to a simple x = 2;).
37 bool fConstantPropagation;
38 std::unique_ptr<Expression>* fExpression;
Ethan Nicholase1d9cb82017-02-06 18:53:07 +000039 const Statement* fStatement;
ethannicholas22f939e2016-10-13 13:25:34 -070040 };
Ethan Nicholas86a43402017-01-19 13:32:00 -050041
ethannicholas22f939e2016-10-13 13:25:34 -070042 std::vector<Node> fNodes;
43 std::set<BlockId> fEntrances;
44 std::set<BlockId> fExits;
45 // variable definitions upon entering this basic block (null expression = undefined)
Ethan Nicholas86a43402017-01-19 13:32:00 -050046 DefinitionMap fBefore;
ethannicholas22f939e2016-10-13 13:25:34 -070047};
48
49struct CFG {
50 BlockId fStart;
51 BlockId fExit;
52 std::vector<BasicBlock> fBlocks;
53
54 void dump();
55
56private:
57 BlockId fCurrent;
58
59 // Adds a new block, adds an exit* from the current block to the new block, then marks the new
60 // block as the current block
61 // *see note in addExit()
62 BlockId newBlock();
63
64 // Adds a new block, but does not mark it current or add an exit from the current block
65 BlockId newIsolatedBlock();
66
67 // Adds an exit from the 'from' block to the 'to' block
68 // Note that we skip adding the exit if the 'from' block is itself unreachable; this means that
69 // we don't actually have to trace the tree to see if a particular block is unreachable, we can
70 // just check to see if it has any entrances. This does require a bit of care in the order in
71 // which we set the CFG up.
72 void addExit(BlockId from, BlockId to);
73
74 friend class CFGGenerator;
75};
76
77/**
78 * Converts functions into control flow graphs.
79 */
80class CFGGenerator {
81public:
82 CFGGenerator() {}
83
Ethan Nicholase1d9cb82017-02-06 18:53:07 +000084 CFG getCFG(const FunctionDefinition& f);
ethannicholas22f939e2016-10-13 13:25:34 -070085
86private:
Ethan Nicholase1d9cb82017-02-06 18:53:07 +000087 void addStatement(CFG& cfg, const Statement* s);
ethannicholas22f939e2016-10-13 13:25:34 -070088
Ethan Nicholas86a43402017-01-19 13:32:00 -050089 void addExpression(CFG& cfg, std::unique_ptr<Expression>* e, bool constantPropagate);
ethannicholas22f939e2016-10-13 13:25:34 -070090
Ethan Nicholas86a43402017-01-19 13:32:00 -050091 void addLValue(CFG& cfg, std::unique_ptr<Expression>* e);
ethannicholas22f939e2016-10-13 13:25:34 -070092
93 std::stack<BlockId> fLoopContinues;
94 std::stack<BlockId> fLoopExits;
95};
96
97}
98
99#endif