/src/solidity/libevmasm/ControlFlowGraph.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | This file is part of solidity. |
3 | | |
4 | | solidity is free software: you can redistribute it and/or modify |
5 | | it under the terms of the GNU General Public License as published by |
6 | | the Free Software Foundation, either version 3 of the License, or |
7 | | (at your option) any later version. |
8 | | |
9 | | solidity is distributed in the hope that it will be useful, |
10 | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
12 | | GNU General Public License for more details. |
13 | | |
14 | | You should have received a copy of the GNU General Public License |
15 | | along with solidity. If not, see <http://www.gnu.org/licenses/>. |
16 | | */ |
17 | | // SPDX-License-Identifier: GPL-3.0 |
18 | | /** |
19 | | * @file ControlFlowGraph.h |
20 | | * @author Christian <c@ethdev.com> |
21 | | * @date 2015 |
22 | | * Control flow analysis for the optimizer. |
23 | | */ |
24 | | |
25 | | #pragma once |
26 | | |
27 | | #include <libsolutil/Common.h> |
28 | | #include <libsolutil/Assertions.h> |
29 | | #include <libevmasm/ExpressionClasses.h> |
30 | | |
31 | | #include <vector> |
32 | | #include <memory> |
33 | | #include <limits> |
34 | | |
35 | | namespace solidity::evmasm |
36 | | { |
37 | | |
38 | | class KnownState; |
39 | | using KnownStatePointer = std::shared_ptr<KnownState>; |
40 | | |
41 | | /** |
42 | | * Identifier for a block, coincides with the tag number of an AssemblyItem but adds a special |
43 | | * ID for the initial block. |
44 | | */ |
45 | | class BlockId |
46 | | { |
47 | | public: |
48 | 0 | BlockId() { *this = invalid(); } |
49 | 0 | explicit BlockId(unsigned _id): m_id(_id) {} |
50 | | explicit BlockId(u256 const& _id); |
51 | 0 | static BlockId initial() { return BlockId(std::numeric_limits<unsigned>::max() - 1); } |
52 | 0 | static BlockId invalid() { return BlockId(std::numeric_limits<unsigned>::max()); } |
53 | | |
54 | 0 | bool operator==(BlockId const& _other) const { return m_id == _other.m_id; } |
55 | 0 | bool operator!=(BlockId const& _other) const { return m_id != _other.m_id; } |
56 | 0 | bool operator<(BlockId const& _other) const { return m_id < _other.m_id; } |
57 | 0 | explicit operator bool() const { return *this != invalid(); } |
58 | | |
59 | | private: |
60 | | unsigned m_id; |
61 | | }; |
62 | | |
63 | | /** |
64 | | * Control flow block inside which instruction counter is always incremented by one |
65 | | * (except for possibly the last instruction). |
66 | | */ |
67 | | struct BasicBlock |
68 | | { |
69 | | /// Start index into assembly item list. |
70 | | unsigned begin = 0; |
71 | | /// End index (excluded) inte assembly item list. |
72 | | unsigned end = 0; |
73 | | /// Tags pushed inside this block, with multiplicity. |
74 | | std::vector<BlockId> pushedTags; |
75 | | /// ID of the block that always follows this one (either non-branching part of JUMPI or flow |
76 | | /// into new block), or BlockId::invalid() otherwise |
77 | | BlockId next = BlockId::invalid(); |
78 | | /// ID of the block that has to precede this one (because control flows into it). |
79 | | BlockId prev = BlockId::invalid(); |
80 | | |
81 | | enum class EndType { JUMP, JUMPI, STOP, HANDOVER }; |
82 | | EndType endType = EndType::HANDOVER; |
83 | | |
84 | | /// Knowledge about the state when this block is entered. Intersection of all possible ways |
85 | | /// to enter this block. |
86 | | KnownStatePointer startState; |
87 | | /// Knowledge about the state at the end of this block. |
88 | | KnownStatePointer endState; |
89 | | }; |
90 | | |
91 | | using BasicBlocks = std::vector<BasicBlock>; |
92 | | |
93 | | /** |
94 | | * Control flow graph optimizer. |
95 | | * ASSUMES THAT WE ONLY JUMP TO TAGS THAT WERE PREVIOUSLY PUSHED. THIS IS NOT TRUE ANYMORE |
96 | | * NOW THAT FUNCTION TAGS CAN BE STORED IN STORAGE. |
97 | | */ |
98 | | class ControlFlowGraph |
99 | | { |
100 | | public: |
101 | | /// Initializes the control flow graph. |
102 | | /// @a _items has to persist across the usage of this class. |
103 | | /// @a _joinKnowledge if true, reduces state knowledge to common base at the join of two paths |
104 | | explicit ControlFlowGraph(AssemblyItems const& _items, bool _joinKnowledge = true): |
105 | | m_items(_items), |
106 | | m_joinKnowledge(_joinKnowledge) |
107 | 0 | {} |
108 | | /// @returns vector of basic blocks in the order they should be used in the final code. |
109 | | /// Should be called only once. |
110 | | BasicBlocks optimisedBlocks(); |
111 | | |
112 | | private: |
113 | | void findLargestTag(); |
114 | | void splitBlocks(); |
115 | | void resolveNextLinks(); |
116 | | void removeUnusedBlocks(); |
117 | | void gatherKnowledge(); |
118 | | void setPrevLinks(); |
119 | | BasicBlocks rebuildCode(); |
120 | | |
121 | | BlockId generateNewId(); |
122 | | |
123 | | unsigned m_lastUsedId = 0; |
124 | | AssemblyItems const& m_items; |
125 | | bool m_joinKnowledge = true; |
126 | | std::map<BlockId, BasicBlock> m_blocks; |
127 | | }; |
128 | | |
129 | | |
130 | | } |