/src/solidity/libyul/optimiser/UnusedStoreEliminator.h
Line | Count | Source |
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 | | * Optimiser component that removes stores to memory and storage slots that are not used |
20 | | * or overwritten later on. |
21 | | */ |
22 | | |
23 | | #pragma once |
24 | | |
25 | | #include <libyul/ASTForward.h> |
26 | | #include <libyul/optimiser/ASTWalker.h> |
27 | | #include <libyul/optimiser/OptimiserStep.h> |
28 | | #include <libyul/optimiser/Semantics.h> |
29 | | #include <libyul/optimiser/UnusedStoreBase.h> |
30 | | #include <libyul/optimiser/KnowledgeBase.h> |
31 | | |
32 | | #include <libevmasm/SemanticInformation.h> |
33 | | |
34 | | #include <map> |
35 | | #include <vector> |
36 | | |
37 | | namespace solidity::yul |
38 | | { |
39 | | class Dialect; |
40 | | struct AssignedValue; |
41 | | |
42 | | /** |
43 | | * Optimizer component that removes sstore and memory store statements if conditions are met for their removal. |
44 | | * In case of an sstore, if all outgoing code paths revert (due to an explicit revert(), invalid(), |
45 | | * or infinite recursion) or lead to another ``sstore`` for which the optimizer can tell that it will overwrite the first store, |
46 | | * the statement will be removed. |
47 | | * |
48 | | * For memory store operations, things are generally simpler, at least in the outermost yul block as all such statements |
49 | | * will be removed if they are never read from in any code path. At function analysis level however, the approach is similar |
50 | | * to sstore, as we don't know whether the memory location will be read once we leave the function's scope, |
51 | | * so the statement will be removed only if all code code paths lead to a memory overwrite. |
52 | | * |
53 | | * Best run in SSA form. |
54 | | * |
55 | | * Prerequisite: Disambiguator, ForLoopInitRewriter. |
56 | | */ |
57 | | class UnusedStoreEliminator: public UnusedStoreBase<UnusedStoreEliminatorKey> |
58 | | { |
59 | | public: |
60 | | static constexpr char const* name{"UnusedStoreEliminator"}; |
61 | | static void run(OptimiserStepContext& _context, Block& _ast); |
62 | | |
63 | | explicit UnusedStoreEliminator( |
64 | | Dialect const& _dialect, |
65 | | std::map<FunctionHandle, SideEffects> const& _functionSideEffects, |
66 | | std::map<YulName, ControlFlowSideEffects> _controlFlowSideEffects, |
67 | | std::map<YulName, AssignedValue> const& _ssaValues, |
68 | | bool _ignoreMemory |
69 | | ); |
70 | | |
71 | | using UnusedStoreBase::operator(); |
72 | | void operator()(FunctionCall const& _functionCall) override; |
73 | | void operator()(FunctionDefinition const&) override; |
74 | | void operator()(Leave const&) override; |
75 | | |
76 | | using UnusedStoreBase::visit; |
77 | | void visit(Statement const& _statement) override; |
78 | | |
79 | | using Location = evmasm::SemanticInformation::Location; |
80 | | using Effect = evmasm::SemanticInformation::Effect; |
81 | | using OperationLength = std::variant<YulName, u256>; |
82 | | struct Operation |
83 | | { |
84 | | Location location; |
85 | | Effect effect; |
86 | | /// Start of affected area. Unknown if not provided. |
87 | | std::optional<YulName> start; |
88 | | /// Length of affected area, unknown if not provided. |
89 | | /// Unused for storage. |
90 | | std::optional<OperationLength> length; |
91 | | }; |
92 | | |
93 | | private: |
94 | 2.82M | std::set<Statement const*>& activeMemoryStores() { return m_activeStores[UnusedStoreEliminatorKey::Memory]; } |
95 | 3.51M | std::set<Statement const*>& activeStorageStores() { return m_activeStores[UnusedStoreEliminatorKey::Storage]; } |
96 | | std::optional<u256> lengthValue(OperationLength const& _length) const |
97 | 5.49M | { |
98 | 5.49M | if (YulName const* length = std::get_if<YulName>(&_length)) |
99 | 829k | return m_knowledgeBase.valueIfKnownConstant(*length); |
100 | 4.66M | else |
101 | 4.66M | return std::get<u256>(_length); |
102 | 5.49M | } |
103 | | |
104 | | void shortcutNestedLoop(ActiveStores const&) override |
105 | 42.3k | { |
106 | | // We might only need to do this for newly introduced stores in the loop. |
107 | 42.3k | markActiveAsUsed(); |
108 | 42.3k | } |
109 | | void finalizeFunctionDefinition(FunctionDefinition const&) override |
110 | 179k | { |
111 | 179k | markActiveAsUsed(); |
112 | 179k | } |
113 | | |
114 | | std::vector<Operation> operationsFromFunctionCall(FunctionCall const& _functionCall) const; |
115 | | void applyOperation(Operation const& _operation); |
116 | | bool knownUnrelated(Operation const& _op1, Operation const& _op2) const; |
117 | | bool knownCovered(Operation const& _covered, Operation const& _covering) const; |
118 | | |
119 | | void markActiveAsUsed(std::optional<Location> _onlyLocation = std::nullopt); |
120 | | void clearActive(std::optional<Location> _onlyLocation = std::nullopt); |
121 | | |
122 | | std::optional<YulName> identifierNameIfSSA(Expression const& _expression) const; |
123 | | |
124 | | bool const m_ignoreMemory; |
125 | | std::map<FunctionHandle, SideEffects> const& m_functionSideEffects; |
126 | | std::map<YulName, ControlFlowSideEffects> m_controlFlowSideEffects; |
127 | | std::map<YulName, AssignedValue> const& m_ssaValues; |
128 | | |
129 | | std::map<Statement const*, Operation> m_storeOperations; |
130 | | |
131 | | KnowledgeBase mutable m_knowledgeBase; |
132 | | }; |
133 | | |
134 | | } |