/src/solidity/libevmasm/PeepholeOptimiser.cpp
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 PeepholeOptimiser.cpp |
20 | | * Performs local optimising code changes to assembly. |
21 | | */ |
22 | | |
23 | | #include <libevmasm/PeepholeOptimiser.h> |
24 | | |
25 | | #include <libevmasm/AssemblyItem.h> |
26 | | #include <libevmasm/SemanticInformation.h> |
27 | | |
28 | | using namespace std; |
29 | | using namespace solidity; |
30 | | using namespace solidity::evmasm; |
31 | | |
32 | | // TODO: Extend this to use the tools from ExpressionClasses.cpp |
33 | | |
34 | | namespace |
35 | | { |
36 | | |
37 | | struct OptimiserState |
38 | | { |
39 | | AssemblyItems const& items; |
40 | | size_t i; |
41 | | std::back_insert_iterator<AssemblyItems> out; |
42 | | }; |
43 | | |
44 | | template<typename FunctionType> |
45 | | struct FunctionParameterCount; |
46 | | template<typename R, typename... Args> |
47 | | struct FunctionParameterCount<R(Args...)> |
48 | | { |
49 | | static constexpr auto value = sizeof...(Args); |
50 | | }; |
51 | | |
52 | | template <class Method> |
53 | | struct SimplePeepholeOptimizerMethod |
54 | | { |
55 | | template <size_t... Indices> |
56 | | static bool applyRule(AssemblyItems::const_iterator _in, back_insert_iterator<AssemblyItems> _out, index_sequence<Indices...>) |
57 | 304M | { |
58 | 304M | return Method::applySimple(_in[Indices]..., _out); |
59 | 304M | } PeepholeOptimiser.cpp:bool (anonymous namespace)::SimplePeepholeOptimizerMethod<(anonymous namespace)::PushPop>::applyRule<0ul, 1ul>(std::__1::__wrap_iter<solidity::evmasm::AssemblyItem const*>, std::__1::back_insert_iterator<std::__1::vector<solidity::evmasm::AssemblyItem, std::__1::allocator<solidity::evmasm::AssemblyItem> > >, std::__1::integer_sequence<unsigned long, 0ul, 1ul>) Line | Count | Source | 57 | 19.0M | { | 58 | 19.0M | return Method::applySimple(_in[Indices]..., _out); | 59 | 19.0M | } |
PeepholeOptimiser.cpp:bool (anonymous namespace)::SimplePeepholeOptimizerMethod<(anonymous namespace)::OpPop>::applyRule<0ul, 1ul>(std::__1::__wrap_iter<solidity::evmasm::AssemblyItem const*>, std::__1::back_insert_iterator<std::__1::vector<solidity::evmasm::AssemblyItem, std::__1::allocator<solidity::evmasm::AssemblyItem> > >, std::__1::integer_sequence<unsigned long, 0ul, 1ul>) Line | Count | Source | 57 | 19.0M | { | 58 | 19.0M | return Method::applySimple(_in[Indices]..., _out); | 59 | 19.0M | } |
PeepholeOptimiser.cpp:bool (anonymous namespace)::SimplePeepholeOptimizerMethod<(anonymous namespace)::OpStop>::applyRule<0ul, 1ul>(std::__1::__wrap_iter<solidity::evmasm::AssemblyItem const*>, std::__1::back_insert_iterator<std::__1::vector<solidity::evmasm::AssemblyItem, std::__1::allocator<solidity::evmasm::AssemblyItem> > >, std::__1::integer_sequence<unsigned long, 0ul, 1ul>) Line | Count | Source | 57 | 19.0M | { | 58 | 19.0M | return Method::applySimple(_in[Indices]..., _out); | 59 | 19.0M | } |
PeepholeOptimiser.cpp:bool (anonymous namespace)::SimplePeepholeOptimizerMethod<(anonymous namespace)::OpReturnRevert>::applyRule<0ul, 1ul, 2ul, 3ul>(std::__1::__wrap_iter<solidity::evmasm::AssemblyItem const*>, std::__1::back_insert_iterator<std::__1::vector<solidity::evmasm::AssemblyItem, std::__1::allocator<solidity::evmasm::AssemblyItem> > >, std::__1::integer_sequence<unsigned long, 0ul, 1ul, 2ul, 3ul>) Line | Count | Source | 57 | 18.9M | { | 58 | 18.9M | return Method::applySimple(_in[Indices]..., _out); | 59 | 18.9M | } |
PeepholeOptimiser.cpp:bool (anonymous namespace)::SimplePeepholeOptimizerMethod<(anonymous namespace)::DoublePush>::applyRule<0ul, 1ul>(std::__1::__wrap_iter<solidity::evmasm::AssemblyItem const*>, std::__1::back_insert_iterator<std::__1::vector<solidity::evmasm::AssemblyItem, std::__1::allocator<solidity::evmasm::AssemblyItem> > >, std::__1::integer_sequence<unsigned long, 0ul, 1ul>) Line | Count | Source | 57 | 19.0M | { | 58 | 19.0M | return Method::applySimple(_in[Indices]..., _out); | 59 | 19.0M | } |
PeepholeOptimiser.cpp:bool (anonymous namespace)::SimplePeepholeOptimizerMethod<(anonymous namespace)::DoubleSwap>::applyRule<0ul, 1ul>(std::__1::__wrap_iter<solidity::evmasm::AssemblyItem const*>, std::__1::back_insert_iterator<std::__1::vector<solidity::evmasm::AssemblyItem, std::__1::allocator<solidity::evmasm::AssemblyItem> > >, std::__1::integer_sequence<unsigned long, 0ul, 1ul>) Line | Count | Source | 57 | 19.0M | { | 58 | 19.0M | return Method::applySimple(_in[Indices]..., _out); | 59 | 19.0M | } |
PeepholeOptimiser.cpp:bool (anonymous namespace)::SimplePeepholeOptimizerMethod<(anonymous namespace)::CommutativeSwap>::applyRule<0ul, 1ul>(std::__1::__wrap_iter<solidity::evmasm::AssemblyItem const*>, std::__1::back_insert_iterator<std::__1::vector<solidity::evmasm::AssemblyItem, std::__1::allocator<solidity::evmasm::AssemblyItem> > >, std::__1::integer_sequence<unsigned long, 0ul, 1ul>) Line | Count | Source | 57 | 19.0M | { | 58 | 19.0M | return Method::applySimple(_in[Indices]..., _out); | 59 | 19.0M | } |
PeepholeOptimiser.cpp:bool (anonymous namespace)::SimplePeepholeOptimizerMethod<(anonymous namespace)::SwapComparison>::applyRule<0ul, 1ul>(std::__1::__wrap_iter<solidity::evmasm::AssemblyItem const*>, std::__1::back_insert_iterator<std::__1::vector<solidity::evmasm::AssemblyItem, std::__1::allocator<solidity::evmasm::AssemblyItem> > >, std::__1::integer_sequence<unsigned long, 0ul, 1ul>) Line | Count | Source | 57 | 19.0M | { | 58 | 19.0M | return Method::applySimple(_in[Indices]..., _out); | 59 | 19.0M | } |
PeepholeOptimiser.cpp:bool (anonymous namespace)::SimplePeepholeOptimizerMethod<(anonymous namespace)::DupSwap>::applyRule<0ul, 1ul>(std::__1::__wrap_iter<solidity::evmasm::AssemblyItem const*>, std::__1::back_insert_iterator<std::__1::vector<solidity::evmasm::AssemblyItem, std::__1::allocator<solidity::evmasm::AssemblyItem> > >, std::__1::integer_sequence<unsigned long, 0ul, 1ul>) Line | Count | Source | 57 | 19.0M | { | 58 | 19.0M | return Method::applySimple(_in[Indices]..., _out); | 59 | 19.0M | } |
PeepholeOptimiser.cpp:bool (anonymous namespace)::SimplePeepholeOptimizerMethod<(anonymous namespace)::IsZeroIsZeroJumpI>::applyRule<0ul, 1ul, 2ul, 3ul>(std::__1::__wrap_iter<solidity::evmasm::AssemblyItem const*>, std::__1::back_insert_iterator<std::__1::vector<solidity::evmasm::AssemblyItem, std::__1::allocator<solidity::evmasm::AssemblyItem> > >, std::__1::integer_sequence<unsigned long, 0ul, 1ul, 2ul, 3ul>) Line | Count | Source | 57 | 18.9M | { | 58 | 18.9M | return Method::applySimple(_in[Indices]..., _out); | 59 | 18.9M | } |
PeepholeOptimiser.cpp:bool (anonymous namespace)::SimplePeepholeOptimizerMethod<(anonymous namespace)::EqIsZeroJumpI>::applyRule<0ul, 1ul, 2ul, 3ul>(std::__1::__wrap_iter<solidity::evmasm::AssemblyItem const*>, std::__1::back_insert_iterator<std::__1::vector<solidity::evmasm::AssemblyItem, std::__1::allocator<solidity::evmasm::AssemblyItem> > >, std::__1::integer_sequence<unsigned long, 0ul, 1ul, 2ul, 3ul>) Line | Count | Source | 57 | 18.9M | { | 58 | 18.9M | return Method::applySimple(_in[Indices]..., _out); | 59 | 18.9M | } |
PeepholeOptimiser.cpp:bool (anonymous namespace)::SimplePeepholeOptimizerMethod<(anonymous namespace)::DoubleJump>::applyRule<0ul, 1ul, 2ul, 3ul, 4ul>(std::__1::__wrap_iter<solidity::evmasm::AssemblyItem const*>, std::__1::back_insert_iterator<std::__1::vector<solidity::evmasm::AssemblyItem, std::__1::allocator<solidity::evmasm::AssemblyItem> > >, std::__1::integer_sequence<unsigned long, 0ul, 1ul, 2ul, 3ul, 4ul>) Line | Count | Source | 57 | 18.8M | { | 58 | 18.8M | return Method::applySimple(_in[Indices]..., _out); | 59 | 18.8M | } |
PeepholeOptimiser.cpp:bool (anonymous namespace)::SimplePeepholeOptimizerMethod<(anonymous namespace)::JumpToNext>::applyRule<0ul, 1ul, 2ul>(std::__1::__wrap_iter<solidity::evmasm::AssemblyItem const*>, std::__1::back_insert_iterator<std::__1::vector<solidity::evmasm::AssemblyItem, std::__1::allocator<solidity::evmasm::AssemblyItem> > >, std::__1::integer_sequence<unsigned long, 0ul, 1ul, 2ul>) Line | Count | Source | 57 | 18.9M | { | 58 | 18.9M | return Method::applySimple(_in[Indices]..., _out); | 59 | 18.9M | } |
PeepholeOptimiser.cpp:bool (anonymous namespace)::SimplePeepholeOptimizerMethod<(anonymous namespace)::TagConjunctions>::applyRule<0ul, 1ul, 2ul>(std::__1::__wrap_iter<solidity::evmasm::AssemblyItem const*>, std::__1::back_insert_iterator<std::__1::vector<solidity::evmasm::AssemblyItem, std::__1::allocator<solidity::evmasm::AssemblyItem> > >, std::__1::integer_sequence<unsigned long, 0ul, 1ul, 2ul>) Line | Count | Source | 57 | 18.9M | { | 58 | 18.9M | return Method::applySimple(_in[Indices]..., _out); | 59 | 18.9M | } |
PeepholeOptimiser.cpp:bool (anonymous namespace)::SimplePeepholeOptimizerMethod<(anonymous namespace)::TruthyAnd>::applyRule<0ul, 1ul, 2ul>(std::__1::__wrap_iter<solidity::evmasm::AssemblyItem const*>, std::__1::back_insert_iterator<std::__1::vector<solidity::evmasm::AssemblyItem, std::__1::allocator<solidity::evmasm::AssemblyItem> > >, std::__1::integer_sequence<unsigned long, 0ul, 1ul, 2ul>) Line | Count | Source | 57 | 18.9M | { | 58 | 18.9M | return Method::applySimple(_in[Indices]..., _out); | 59 | 18.9M | } |
PeepholeOptimiser.cpp:bool (anonymous namespace)::SimplePeepholeOptimizerMethod<(anonymous namespace)::Identity>::applyRule<0ul>(std::__1::__wrap_iter<solidity::evmasm::AssemblyItem const*>, std::__1::back_insert_iterator<std::__1::vector<solidity::evmasm::AssemblyItem, std::__1::allocator<solidity::evmasm::AssemblyItem> > >, std::__1::integer_sequence<unsigned long, 0ul>) Line | Count | Source | 57 | 19.0M | { | 58 | 19.0M | return Method::applySimple(_in[Indices]..., _out); | 59 | 19.0M | } |
|
60 | | static bool apply(OptimiserState& _state) |
61 | 305M | { |
62 | 305M | static constexpr size_t WindowSize = FunctionParameterCount<decltype(Method::applySimple)>::value - 1; |
63 | 305M | if ( |
64 | 305M | _state.i + WindowSize <= _state.items.size() && |
65 | 305M | applyRule(_state.items.begin() + static_cast<ptrdiff_t>(_state.i), _state.out, make_index_sequence<WindowSize>{}) |
66 | 305M | ) |
67 | 19.1M | { |
68 | 19.1M | _state.i += WindowSize; |
69 | 19.1M | return true; |
70 | 19.1M | } |
71 | 286M | else |
72 | 286M | return false; |
73 | 305M | } PeepholeOptimiser.cpp:(anonymous namespace)::SimplePeepholeOptimizerMethod<(anonymous namespace)::PushPop>::apply((anonymous namespace)::OptimiserState&) Line | Count | Source | 61 | 19.1M | { | 62 | 19.1M | static constexpr size_t WindowSize = FunctionParameterCount<decltype(Method::applySimple)>::value - 1; | 63 | 19.1M | if ( | 64 | 19.1M | _state.i + WindowSize <= _state.items.size() && | 65 | 19.1M | applyRule(_state.items.begin() + static_cast<ptrdiff_t>(_state.i), _state.out, make_index_sequence<WindowSize>{}) | 66 | 19.1M | ) | 67 | 23.5k | { | 68 | 23.5k | _state.i += WindowSize; | 69 | 23.5k | return true; | 70 | 23.5k | } | 71 | 19.1M | else | 72 | 19.1M | return false; | 73 | 19.1M | } |
PeepholeOptimiser.cpp:(anonymous namespace)::SimplePeepholeOptimizerMethod<(anonymous namespace)::OpPop>::apply((anonymous namespace)::OptimiserState&) Line | Count | Source | 61 | 19.1M | { | 62 | 19.1M | static constexpr size_t WindowSize = FunctionParameterCount<decltype(Method::applySimple)>::value - 1; | 63 | 19.1M | if ( | 64 | 19.1M | _state.i + WindowSize <= _state.items.size() && | 65 | 19.1M | applyRule(_state.items.begin() + static_cast<ptrdiff_t>(_state.i), _state.out, make_index_sequence<WindowSize>{}) | 66 | 19.1M | ) | 67 | 8.89k | { | 68 | 8.89k | _state.i += WindowSize; | 69 | 8.89k | return true; | 70 | 8.89k | } | 71 | 19.1M | else | 72 | 19.1M | return false; | 73 | 19.1M | } |
PeepholeOptimiser.cpp:(anonymous namespace)::SimplePeepholeOptimizerMethod<(anonymous namespace)::OpStop>::apply((anonymous namespace)::OptimiserState&) Line | Count | Source | 61 | 19.1M | { | 62 | 19.1M | static constexpr size_t WindowSize = FunctionParameterCount<decltype(Method::applySimple)>::value - 1; | 63 | 19.1M | if ( | 64 | 19.1M | _state.i + WindowSize <= _state.items.size() && | 65 | 19.1M | applyRule(_state.items.begin() + static_cast<ptrdiff_t>(_state.i), _state.out, make_index_sequence<WindowSize>{}) | 66 | 19.1M | ) | 67 | 849 | { | 68 | 849 | _state.i += WindowSize; | 69 | 849 | return true; | 70 | 849 | } | 71 | 19.1M | else | 72 | 19.1M | return false; | 73 | 19.1M | } |
PeepholeOptimiser.cpp:(anonymous namespace)::SimplePeepholeOptimizerMethod<(anonymous namespace)::OpReturnRevert>::apply((anonymous namespace)::OptimiserState&) Line | Count | Source | 61 | 19.1M | { | 62 | 19.1M | static constexpr size_t WindowSize = FunctionParameterCount<decltype(Method::applySimple)>::value - 1; | 63 | 19.1M | if ( | 64 | 19.1M | _state.i + WindowSize <= _state.items.size() && | 65 | 19.1M | applyRule(_state.items.begin() + static_cast<ptrdiff_t>(_state.i), _state.out, make_index_sequence<WindowSize>{}) | 66 | 19.1M | ) | 67 | 103 | { | 68 | 103 | _state.i += WindowSize; | 69 | 103 | return true; | 70 | 103 | } | 71 | 19.1M | else | 72 | 19.1M | return false; | 73 | 19.1M | } |
PeepholeOptimiser.cpp:(anonymous namespace)::SimplePeepholeOptimizerMethod<(anonymous namespace)::DoublePush>::apply((anonymous namespace)::OptimiserState&) Line | Count | Source | 61 | 19.1M | { | 62 | 19.1M | static constexpr size_t WindowSize = FunctionParameterCount<decltype(Method::applySimple)>::value - 1; | 63 | 19.1M | if ( | 64 | 19.1M | _state.i + WindowSize <= _state.items.size() && | 65 | 19.1M | applyRule(_state.items.begin() + static_cast<ptrdiff_t>(_state.i), _state.out, make_index_sequence<WindowSize>{}) | 66 | 19.1M | ) | 67 | 25.0k | { | 68 | 25.0k | _state.i += WindowSize; | 69 | 25.0k | return true; | 70 | 25.0k | } | 71 | 19.0M | else | 72 | 19.0M | return false; | 73 | 19.1M | } |
PeepholeOptimiser.cpp:(anonymous namespace)::SimplePeepholeOptimizerMethod<(anonymous namespace)::DoubleSwap>::apply((anonymous namespace)::OptimiserState&) Line | Count | Source | 61 | 19.0M | { | 62 | 19.0M | static constexpr size_t WindowSize = FunctionParameterCount<decltype(Method::applySimple)>::value - 1; | 63 | 19.0M | if ( | 64 | 19.0M | _state.i + WindowSize <= _state.items.size() && | 65 | 19.0M | applyRule(_state.items.begin() + static_cast<ptrdiff_t>(_state.i), _state.out, make_index_sequence<WindowSize>{}) | 66 | 19.0M | ) | 67 | 46 | { | 68 | 46 | _state.i += WindowSize; | 69 | 46 | return true; | 70 | 46 | } | 71 | 19.0M | else | 72 | 19.0M | return false; | 73 | 19.0M | } |
PeepholeOptimiser.cpp:(anonymous namespace)::SimplePeepholeOptimizerMethod<(anonymous namespace)::CommutativeSwap>::apply((anonymous namespace)::OptimiserState&) Line | Count | Source | 61 | 19.0M | { | 62 | 19.0M | static constexpr size_t WindowSize = FunctionParameterCount<decltype(Method::applySimple)>::value - 1; | 63 | 19.0M | if ( | 64 | 19.0M | _state.i + WindowSize <= _state.items.size() && | 65 | 19.0M | applyRule(_state.items.begin() + static_cast<ptrdiff_t>(_state.i), _state.out, make_index_sequence<WindowSize>{}) | 66 | 19.0M | ) | 67 | 3.82k | { | 68 | 3.82k | _state.i += WindowSize; | 69 | 3.82k | return true; | 70 | 3.82k | } | 71 | 19.0M | else | 72 | 19.0M | return false; | 73 | 19.0M | } |
PeepholeOptimiser.cpp:(anonymous namespace)::SimplePeepholeOptimizerMethod<(anonymous namespace)::SwapComparison>::apply((anonymous namespace)::OptimiserState&) Line | Count | Source | 61 | 19.0M | { | 62 | 19.0M | static constexpr size_t WindowSize = FunctionParameterCount<decltype(Method::applySimple)>::value - 1; | 63 | 19.0M | if ( | 64 | 19.0M | _state.i + WindowSize <= _state.items.size() && | 65 | 19.0M | applyRule(_state.items.begin() + static_cast<ptrdiff_t>(_state.i), _state.out, make_index_sequence<WindowSize>{}) | 66 | 19.0M | ) | 67 | 598 | { | 68 | 598 | _state.i += WindowSize; | 69 | 598 | return true; | 70 | 598 | } | 71 | 19.0M | else | 72 | 19.0M | return false; | 73 | 19.0M | } |
PeepholeOptimiser.cpp:(anonymous namespace)::SimplePeepholeOptimizerMethod<(anonymous namespace)::DupSwap>::apply((anonymous namespace)::OptimiserState&) Line | Count | Source | 61 | 19.0M | { | 62 | 19.0M | static constexpr size_t WindowSize = FunctionParameterCount<decltype(Method::applySimple)>::value - 1; | 63 | 19.0M | if ( | 64 | 19.0M | _state.i + WindowSize <= _state.items.size() && | 65 | 19.0M | applyRule(_state.items.begin() + static_cast<ptrdiff_t>(_state.i), _state.out, make_index_sequence<WindowSize>{}) | 66 | 19.0M | ) | 67 | 1.17k | { | 68 | 1.17k | _state.i += WindowSize; | 69 | 1.17k | return true; | 70 | 1.17k | } | 71 | 19.0M | else | 72 | 19.0M | return false; | 73 | 19.0M | } |
PeepholeOptimiser.cpp:(anonymous namespace)::SimplePeepholeOptimizerMethod<(anonymous namespace)::IsZeroIsZeroJumpI>::apply((anonymous namespace)::OptimiserState&) Line | Count | Source | 61 | 19.0M | { | 62 | 19.0M | static constexpr size_t WindowSize = FunctionParameterCount<decltype(Method::applySimple)>::value - 1; | 63 | 19.0M | if ( | 64 | 19.0M | _state.i + WindowSize <= _state.items.size() && | 65 | 19.0M | applyRule(_state.items.begin() + static_cast<ptrdiff_t>(_state.i), _state.out, make_index_sequence<WindowSize>{}) | 66 | 19.0M | ) | 67 | 55 | { | 68 | 55 | _state.i += WindowSize; | 69 | 55 | return true; | 70 | 55 | } | 71 | 19.0M | else | 72 | 19.0M | return false; | 73 | 19.0M | } |
PeepholeOptimiser.cpp:(anonymous namespace)::SimplePeepholeOptimizerMethod<(anonymous namespace)::EqIsZeroJumpI>::apply((anonymous namespace)::OptimiserState&) Line | Count | Source | 61 | 19.0M | { | 62 | 19.0M | static constexpr size_t WindowSize = FunctionParameterCount<decltype(Method::applySimple)>::value - 1; | 63 | 19.0M | if ( | 64 | 19.0M | _state.i + WindowSize <= _state.items.size() && | 65 | 19.0M | applyRule(_state.items.begin() + static_cast<ptrdiff_t>(_state.i), _state.out, make_index_sequence<WindowSize>{}) | 66 | 19.0M | ) | 67 | 886 | { | 68 | 886 | _state.i += WindowSize; | 69 | 886 | return true; | 70 | 886 | } | 71 | 19.0M | else | 72 | 19.0M | return false; | 73 | 19.0M | } |
PeepholeOptimiser.cpp:(anonymous namespace)::SimplePeepholeOptimizerMethod<(anonymous namespace)::DoubleJump>::apply((anonymous namespace)::OptimiserState&) Line | Count | Source | 61 | 19.0M | { | 62 | 19.0M | static constexpr size_t WindowSize = FunctionParameterCount<decltype(Method::applySimple)>::value - 1; | 63 | 19.0M | if ( | 64 | 19.0M | _state.i + WindowSize <= _state.items.size() && | 65 | 19.0M | applyRule(_state.items.begin() + static_cast<ptrdiff_t>(_state.i), _state.out, make_index_sequence<WindowSize>{}) | 66 | 19.0M | ) | 67 | 985 | { | 68 | 985 | _state.i += WindowSize; | 69 | 985 | return true; | 70 | 985 | } | 71 | 19.0M | else | 72 | 19.0M | return false; | 73 | 19.0M | } |
PeepholeOptimiser.cpp:(anonymous namespace)::SimplePeepholeOptimizerMethod<(anonymous namespace)::JumpToNext>::apply((anonymous namespace)::OptimiserState&) Line | Count | Source | 61 | 19.0M | { | 62 | 19.0M | static constexpr size_t WindowSize = FunctionParameterCount<decltype(Method::applySimple)>::value - 1; | 63 | 19.0M | if ( | 64 | 19.0M | _state.i + WindowSize <= _state.items.size() && | 65 | 19.0M | applyRule(_state.items.begin() + static_cast<ptrdiff_t>(_state.i), _state.out, make_index_sequence<WindowSize>{}) | 66 | 19.0M | ) | 67 | 29.5k | { | 68 | 29.5k | _state.i += WindowSize; | 69 | 29.5k | return true; | 70 | 29.5k | } | 71 | 19.0M | else | 72 | 19.0M | return false; | 73 | 19.0M | } |
PeepholeOptimiser.cpp:(anonymous namespace)::SimplePeepholeOptimizerMethod<(anonymous namespace)::TagConjunctions>::apply((anonymous namespace)::OptimiserState&) Line | Count | Source | 61 | 19.0M | { | 62 | 19.0M | static constexpr size_t WindowSize = FunctionParameterCount<decltype(Method::applySimple)>::value - 1; | 63 | 19.0M | if ( | 64 | 19.0M | _state.i + WindowSize <= _state.items.size() && | 65 | 19.0M | applyRule(_state.items.begin() + static_cast<ptrdiff_t>(_state.i), _state.out, make_index_sequence<WindowSize>{}) | 66 | 19.0M | ) | 67 | 0 | { | 68 | 0 | _state.i += WindowSize; | 69 | 0 | return true; | 70 | 0 | } | 71 | 19.0M | else | 72 | 19.0M | return false; | 73 | 19.0M | } |
PeepholeOptimiser.cpp:(anonymous namespace)::SimplePeepholeOptimizerMethod<(anonymous namespace)::TruthyAnd>::apply((anonymous namespace)::OptimiserState&) Line | Count | Source | 61 | 19.0M | { | 62 | 19.0M | static constexpr size_t WindowSize = FunctionParameterCount<decltype(Method::applySimple)>::value - 1; | 63 | 19.0M | if ( | 64 | 19.0M | _state.i + WindowSize <= _state.items.size() && | 65 | 19.0M | applyRule(_state.items.begin() + static_cast<ptrdiff_t>(_state.i), _state.out, make_index_sequence<WindowSize>{}) | 66 | 19.0M | ) | 67 | 2 | { | 68 | 2 | _state.i += WindowSize; | 69 | 2 | return true; | 70 | 2 | } | 71 | 19.0M | else | 72 | 19.0M | return false; | 73 | 19.0M | } |
PeepholeOptimiser.cpp:(anonymous namespace)::SimplePeepholeOptimizerMethod<(anonymous namespace)::Identity>::apply((anonymous namespace)::OptimiserState&) Line | Count | Source | 61 | 19.0M | { | 62 | 19.0M | static constexpr size_t WindowSize = FunctionParameterCount<decltype(Method::applySimple)>::value - 1; | 63 | 19.0M | if ( | 64 | 19.0M | _state.i + WindowSize <= _state.items.size() && | 65 | 19.0M | applyRule(_state.items.begin() + static_cast<ptrdiff_t>(_state.i), _state.out, make_index_sequence<WindowSize>{}) | 66 | 19.0M | ) | 67 | 19.0M | { | 68 | 19.0M | _state.i += WindowSize; | 69 | 19.0M | return true; | 70 | 19.0M | } | 71 | 0 | else | 72 | 0 | return false; | 73 | 19.0M | } |
|
74 | | }; |
75 | | |
76 | | struct Identity: SimplePeepholeOptimizerMethod<Identity> |
77 | | { |
78 | | static bool applySimple(AssemblyItem const& _item, std::back_insert_iterator<AssemblyItems> _out) |
79 | 19.0M | { |
80 | 19.0M | *_out = _item; |
81 | 19.0M | return true; |
82 | 19.0M | } |
83 | | }; |
84 | | |
85 | | struct PushPop: SimplePeepholeOptimizerMethod<PushPop> |
86 | | { |
87 | | static bool applySimple(AssemblyItem const& _push, AssemblyItem const& _pop, std::back_insert_iterator<AssemblyItems>) |
88 | 19.0M | { |
89 | 19.0M | auto t = _push.type(); |
90 | 19.0M | return _pop == Instruction::POP && ( |
91 | 1.75M | SemanticInformation::isDupInstruction(_push) || |
92 | 1.75M | t == Push || t == PushTag || t == PushSub || |
93 | 1.75M | t == PushSubSize || t == PushProgramSize || t == PushData || t == PushLibraryAddress |
94 | 1.75M | ); |
95 | 19.0M | } |
96 | | }; |
97 | | |
98 | | struct OpPop: SimplePeepholeOptimizerMethod<OpPop> |
99 | | { |
100 | | static bool applySimple( |
101 | | AssemblyItem const& _op, |
102 | | AssemblyItem const& _pop, |
103 | | std::back_insert_iterator<AssemblyItems> _out |
104 | | ) |
105 | 19.0M | { |
106 | 19.0M | if (_pop == Instruction::POP && _op.type() == Operation) |
107 | 1.60M | { |
108 | 1.60M | Instruction instr = _op.instruction(); |
109 | 1.60M | if (instructionInfo(instr).ret == 1 && !instructionInfo(instr).sideEffects) |
110 | 8.89k | { |
111 | 21.6k | for (int j = 0; j < instructionInfo(instr).args; j++) |
112 | 12.7k | *_out = {Instruction::POP, _op.location()}; |
113 | 8.89k | return true; |
114 | 8.89k | } |
115 | 1.60M | } |
116 | 19.0M | return false; |
117 | 19.0M | } |
118 | | }; |
119 | | |
120 | | struct OpStop: SimplePeepholeOptimizerMethod<OpStop> |
121 | | { |
122 | | static bool applySimple( |
123 | | AssemblyItem const& _op, |
124 | | AssemblyItem const& _stop, |
125 | | std::back_insert_iterator<AssemblyItems> _out |
126 | | ) |
127 | 19.0M | { |
128 | 19.0M | if (_stop == Instruction::STOP) |
129 | 13.4k | { |
130 | 13.4k | if (_op.type() == Operation) |
131 | 9.30k | { |
132 | 9.30k | Instruction instr = _op.instruction(); |
133 | 9.30k | if (!instructionInfo(instr).sideEffects) |
134 | 823 | { |
135 | 823 | *_out = {Instruction::STOP, _op.location()}; |
136 | 823 | return true; |
137 | 823 | } |
138 | 9.30k | } |
139 | 4.10k | else if (_op.type() == Push) |
140 | 26 | { |
141 | 26 | *_out = {Instruction::STOP, _op.location()}; |
142 | 26 | return true; |
143 | 26 | } |
144 | 13.4k | } |
145 | 19.0M | return false; |
146 | 19.0M | } |
147 | | }; |
148 | | |
149 | | struct OpReturnRevert: SimplePeepholeOptimizerMethod<OpReturnRevert> |
150 | | { |
151 | | static bool applySimple( |
152 | | AssemblyItem const& _op, |
153 | | AssemblyItem const& _push, |
154 | | AssemblyItem const& _pushOrDup, |
155 | | AssemblyItem const& _returnRevert, |
156 | | std::back_insert_iterator<AssemblyItems> _out |
157 | | ) |
158 | 18.9M | { |
159 | 18.9M | if ( |
160 | 18.9M | (_returnRevert == Instruction::RETURN || _returnRevert == Instruction::REVERT) && |
161 | 18.9M | _push.type() == Push && |
162 | 18.9M | (_pushOrDup.type() == Push || _pushOrDup == dupInstruction(1)) |
163 | 18.9M | ) |
164 | 2.59k | if ( |
165 | 2.59k | (_op.type() == Operation && !instructionInfo(_op.instruction()).sideEffects) || |
166 | 2.59k | _op.type() == Push |
167 | 2.59k | ) |
168 | 103 | { |
169 | 103 | *_out = _push; |
170 | 103 | *_out = _pushOrDup; |
171 | 103 | *_out = _returnRevert; |
172 | 103 | return true; |
173 | 103 | } |
174 | 18.9M | return false; |
175 | 18.9M | } |
176 | | }; |
177 | | |
178 | | struct DoubleSwap: SimplePeepholeOptimizerMethod<DoubleSwap> |
179 | | { |
180 | | static size_t applySimple(AssemblyItem const& _s1, AssemblyItem const& _s2, std::back_insert_iterator<AssemblyItems>) |
181 | 19.0M | { |
182 | 19.0M | return _s1 == _s2 && SemanticInformation::isSwapInstruction(_s1); |
183 | 19.0M | } |
184 | | }; |
185 | | |
186 | | struct DoublePush: SimplePeepholeOptimizerMethod<DoublePush> |
187 | | { |
188 | | static bool applySimple(AssemblyItem const& _push1, AssemblyItem const& _push2, std::back_insert_iterator<AssemblyItems> _out) |
189 | 19.0M | { |
190 | 19.0M | if (_push1.type() == Push && _push2.type() == Push && _push1.data() == _push2.data()) |
191 | 25.0k | { |
192 | 25.0k | *_out = _push1; |
193 | 25.0k | *_out = {Instruction::DUP1, _push2.location()}; |
194 | 25.0k | return true; |
195 | 25.0k | } |
196 | 19.0M | else |
197 | 19.0M | return false; |
198 | 19.0M | } |
199 | | }; |
200 | | |
201 | | struct CommutativeSwap: SimplePeepholeOptimizerMethod<CommutativeSwap> |
202 | | { |
203 | | static bool applySimple(AssemblyItem const& _swap, AssemblyItem const& _op, std::back_insert_iterator<AssemblyItems> _out) |
204 | 19.0M | { |
205 | | // Remove SWAP1 if following instruction is commutative |
206 | 19.0M | if ( |
207 | 19.0M | _swap == Instruction::SWAP1 && |
208 | 19.0M | SemanticInformation::isCommutativeOperation(_op) |
209 | 19.0M | ) |
210 | 3.82k | { |
211 | 3.82k | *_out = _op; |
212 | 3.82k | return true; |
213 | 3.82k | } |
214 | 19.0M | else |
215 | 19.0M | return false; |
216 | 19.0M | } |
217 | | }; |
218 | | |
219 | | struct SwapComparison: SimplePeepholeOptimizerMethod<SwapComparison> |
220 | | { |
221 | | static bool applySimple(AssemblyItem const& _swap, AssemblyItem const& _op, std::back_insert_iterator<AssemblyItems> _out) |
222 | 19.0M | { |
223 | 19.0M | static map<Instruction, Instruction> const swappableOps{ |
224 | 19.0M | { Instruction::LT, Instruction::GT }, |
225 | 19.0M | { Instruction::GT, Instruction::LT }, |
226 | 19.0M | { Instruction::SLT, Instruction::SGT }, |
227 | 19.0M | { Instruction::SGT, Instruction::SLT } |
228 | 19.0M | }; |
229 | | |
230 | 19.0M | if ( |
231 | 19.0M | _swap == Instruction::SWAP1 && |
232 | 19.0M | _op.type() == Operation && |
233 | 19.0M | swappableOps.count(_op.instruction()) |
234 | 19.0M | ) |
235 | 598 | { |
236 | 598 | *_out = swappableOps.at(_op.instruction()); |
237 | 598 | return true; |
238 | 598 | } |
239 | 19.0M | else |
240 | 19.0M | return false; |
241 | 19.0M | } |
242 | | }; |
243 | | |
244 | | /// Remove swapN after dupN |
245 | | struct DupSwap: SimplePeepholeOptimizerMethod<DupSwap> |
246 | | { |
247 | | static size_t applySimple( |
248 | | AssemblyItem const& _dupN, |
249 | | AssemblyItem const& _swapN, |
250 | | std::back_insert_iterator<AssemblyItems> _out |
251 | | ) |
252 | 19.0M | { |
253 | 19.0M | if ( |
254 | 19.0M | SemanticInformation::isDupInstruction(_dupN) && |
255 | 19.0M | SemanticInformation::isSwapInstruction(_swapN) && |
256 | 19.0M | getDupNumber(_dupN.instruction()) == getSwapNumber(_swapN.instruction()) |
257 | 19.0M | ) |
258 | 1.17k | { |
259 | 1.17k | *_out = _dupN; |
260 | 1.17k | return true; |
261 | 1.17k | } |
262 | 19.0M | else |
263 | 19.0M | return false; |
264 | 19.0M | } |
265 | | }; |
266 | | |
267 | | |
268 | | struct IsZeroIsZeroJumpI: SimplePeepholeOptimizerMethod<IsZeroIsZeroJumpI> |
269 | | { |
270 | | static size_t applySimple( |
271 | | AssemblyItem const& _iszero1, |
272 | | AssemblyItem const& _iszero2, |
273 | | AssemblyItem const& _pushTag, |
274 | | AssemblyItem const& _jumpi, |
275 | | std::back_insert_iterator<AssemblyItems> _out |
276 | | ) |
277 | 18.9M | { |
278 | 18.9M | if ( |
279 | 18.9M | _iszero1 == Instruction::ISZERO && |
280 | 18.9M | _iszero2 == Instruction::ISZERO && |
281 | 18.9M | _pushTag.type() == PushTag && |
282 | 18.9M | _jumpi == Instruction::JUMPI |
283 | 18.9M | ) |
284 | 55 | { |
285 | 55 | *_out = _pushTag; |
286 | 55 | *_out = _jumpi; |
287 | 55 | return true; |
288 | 55 | } |
289 | 18.9M | else |
290 | 18.9M | return false; |
291 | 18.9M | } |
292 | | }; |
293 | | |
294 | | struct EqIsZeroJumpI: SimplePeepholeOptimizerMethod<EqIsZeroJumpI> |
295 | | { |
296 | | static size_t applySimple( |
297 | | AssemblyItem const& _eq, |
298 | | AssemblyItem const& _iszero, |
299 | | AssemblyItem const& _pushTag, |
300 | | AssemblyItem const& _jumpi, |
301 | | std::back_insert_iterator<AssemblyItems> _out |
302 | | ) |
303 | 18.9M | { |
304 | 18.9M | if ( |
305 | 18.9M | _eq == Instruction::EQ && |
306 | 18.9M | _iszero == Instruction::ISZERO && |
307 | 18.9M | _pushTag.type() == PushTag && |
308 | 18.9M | _jumpi == Instruction::JUMPI |
309 | 18.9M | ) |
310 | 886 | { |
311 | 886 | *_out = AssemblyItem(Instruction::SUB, _eq.location()); |
312 | 886 | *_out = _pushTag; |
313 | 886 | *_out = _jumpi; |
314 | 886 | return true; |
315 | 886 | } |
316 | 18.9M | else |
317 | 18.9M | return false; |
318 | 18.9M | } |
319 | | }; |
320 | | |
321 | | // push_tag_1 jumpi push_tag_2 jump tag_1: -> iszero push_tag_2 jumpi tag_1: |
322 | | struct DoubleJump: SimplePeepholeOptimizerMethod<DoubleJump> |
323 | | { |
324 | | static size_t applySimple( |
325 | | AssemblyItem const& _pushTag1, |
326 | | AssemblyItem const& _jumpi, |
327 | | AssemblyItem const& _pushTag2, |
328 | | AssemblyItem const& _jump, |
329 | | AssemblyItem const& _tag1, |
330 | | std::back_insert_iterator<AssemblyItems> _out |
331 | | ) |
332 | 18.8M | { |
333 | 18.8M | if ( |
334 | 18.8M | _pushTag1.type() == PushTag && |
335 | 18.8M | _jumpi == Instruction::JUMPI && |
336 | 18.8M | _pushTag2.type() == PushTag && |
337 | 18.8M | _jump == Instruction::JUMP && |
338 | 18.8M | _tag1.type() == Tag && |
339 | 18.8M | _pushTag1.data() == _tag1.data() |
340 | 18.8M | ) |
341 | 985 | { |
342 | 985 | *_out = AssemblyItem(Instruction::ISZERO, _jumpi.location()); |
343 | 985 | *_out = _pushTag2; |
344 | 985 | *_out = _jumpi; |
345 | 985 | *_out = _tag1; |
346 | 985 | return true; |
347 | 985 | } |
348 | 18.8M | else |
349 | 18.8M | return false; |
350 | 18.8M | } |
351 | | }; |
352 | | |
353 | | struct JumpToNext: SimplePeepholeOptimizerMethod<JumpToNext> |
354 | | { |
355 | | static size_t applySimple( |
356 | | AssemblyItem const& _pushTag, |
357 | | AssemblyItem const& _jump, |
358 | | AssemblyItem const& _tag, |
359 | | std::back_insert_iterator<AssemblyItems> _out |
360 | | ) |
361 | 18.9M | { |
362 | 18.9M | if ( |
363 | 18.9M | _pushTag.type() == PushTag && |
364 | 18.9M | (_jump == Instruction::JUMP || _jump == Instruction::JUMPI) && |
365 | 18.9M | _tag.type() == Tag && |
366 | 18.9M | _pushTag.data() == _tag.data() |
367 | 18.9M | ) |
368 | 29.5k | { |
369 | 29.5k | if (_jump == Instruction::JUMPI) |
370 | 3.05k | *_out = AssemblyItem(Instruction::POP, _jump.location()); |
371 | 29.5k | *_out = _tag; |
372 | 29.5k | return true; |
373 | 29.5k | } |
374 | 18.9M | else |
375 | 18.9M | return false; |
376 | 18.9M | } |
377 | | }; |
378 | | |
379 | | struct TagConjunctions: SimplePeepholeOptimizerMethod<TagConjunctions> |
380 | | { |
381 | | static bool applySimple( |
382 | | AssemblyItem const& _pushTag, |
383 | | AssemblyItem const& _pushConstant, |
384 | | AssemblyItem const& _and, |
385 | | std::back_insert_iterator<AssemblyItems> _out |
386 | | ) |
387 | 18.9M | { |
388 | 18.9M | if (_and != Instruction::AND) |
389 | 18.9M | return false; |
390 | 5.99k | if ( |
391 | 5.99k | _pushTag.type() == PushTag && |
392 | 5.99k | _pushConstant.type() == Push && |
393 | 5.99k | (_pushConstant.data() & u256(0xFFFFFFFF)) == u256(0xFFFFFFFF) |
394 | 5.99k | ) |
395 | 0 | { |
396 | 0 | *_out = _pushTag; |
397 | 0 | return true; |
398 | 0 | } |
399 | 5.99k | else if ( |
400 | | // tag and constant are swapped |
401 | 5.99k | _pushConstant.type() == PushTag && |
402 | 5.99k | _pushTag.type() == Push && |
403 | 5.99k | (_pushTag.data() & u256(0xFFFFFFFF)) == u256(0xFFFFFFFF) |
404 | 5.99k | ) |
405 | 0 | { |
406 | 0 | *_out = _pushConstant; |
407 | 0 | return true; |
408 | 0 | } |
409 | 5.99k | else |
410 | 5.99k | return false; |
411 | 5.99k | } |
412 | | }; |
413 | | |
414 | | struct TruthyAnd: SimplePeepholeOptimizerMethod<TruthyAnd> |
415 | | { |
416 | | static bool applySimple( |
417 | | AssemblyItem const& _push, |
418 | | AssemblyItem const& _not, |
419 | | AssemblyItem const& _and, |
420 | | std::back_insert_iterator<AssemblyItems> |
421 | | ) |
422 | 18.9M | { |
423 | 18.9M | return ( |
424 | 18.9M | _push.type() == Push && _push.data() == 0 && |
425 | 18.9M | _not == Instruction::NOT && |
426 | 18.9M | _and == Instruction::AND |
427 | 18.9M | ); |
428 | 18.9M | } |
429 | | }; |
430 | | |
431 | | /// Removes everything after a JUMP (or similar) until the next JUMPDEST. |
432 | | struct UnreachableCode |
433 | | { |
434 | | static bool apply(OptimiserState& _state) |
435 | 19.0M | { |
436 | 19.0M | auto it = _state.items.begin() + static_cast<ptrdiff_t>(_state.i); |
437 | 19.0M | auto end = _state.items.end(); |
438 | 19.0M | if (it == end) |
439 | 0 | return false; |
440 | 19.0M | if ( |
441 | 19.0M | it[0] != Instruction::JUMP && |
442 | 19.0M | it[0] != Instruction::RETURN && |
443 | 19.0M | it[0] != Instruction::STOP && |
444 | 19.0M | it[0] != Instruction::INVALID && |
445 | 19.0M | it[0] != Instruction::SELFDESTRUCT && |
446 | 19.0M | it[0] != Instruction::REVERT |
447 | 19.0M | ) |
448 | 17.9M | return false; |
449 | | |
450 | 1.06M | ptrdiff_t i = 1; |
451 | 1.39M | while (it + i != end && it[i].type() != Tag) |
452 | 327k | i++; |
453 | 1.06M | if (i > 1) |
454 | 20.9k | { |
455 | 20.9k | *_state.out = it[0]; |
456 | 20.9k | _state.i += static_cast<size_t>(i); |
457 | 20.9k | return true; |
458 | 20.9k | } |
459 | 1.04M | else |
460 | 1.04M | return false; |
461 | 1.06M | } |
462 | | }; |
463 | | |
464 | | void applyMethods(OptimiserState&) |
465 | 0 | { |
466 | 0 | assertThrow(false, OptimizerException, "Peephole optimizer failed to apply identity."); |
467 | 0 | } |
468 | | |
469 | | template <typename Method, typename... OtherMethods> |
470 | | void applyMethods(OptimiserState& _state, Method, OtherMethods... _other) |
471 | 324M | { |
472 | 324M | if (!Method::apply(_state)) |
473 | 305M | applyMethods(_state, _other...); |
474 | 324M | } PeepholeOptimiser.cpp:void (anonymous namespace)::applyMethods<(anonymous namespace)::PushPop, (anonymous namespace)::OpPop, (anonymous namespace)::OpStop, (anonymous namespace)::OpReturnRevert, (anonymous namespace)::DoublePush, (anonymous namespace)::DoubleSwap, (anonymous namespace)::CommutativeSwap, (anonymous namespace)::SwapComparison, (anonymous namespace)::DupSwap, (anonymous namespace)::IsZeroIsZeroJumpI, (anonymous namespace)::EqIsZeroJumpI, (anonymous namespace)::DoubleJump, (anonymous namespace)::JumpToNext, (anonymous namespace)::UnreachableCode, (anonymous namespace)::TagConjunctions, (anonymous namespace)::TruthyAnd, (anonymous namespace)::Identity>((anonymous namespace)::OptimiserState&, (anonymous namespace)::PushPop, (anonymous namespace)::OpPop, (anonymous namespace)::OpStop, (anonymous namespace)::OpReturnRevert, (anonymous namespace)::DoublePush, (anonymous namespace)::DoubleSwap, (anonymous namespace)::CommutativeSwap, (anonymous namespace)::SwapComparison, (anonymous namespace)::DupSwap, (anonymous namespace)::IsZeroIsZeroJumpI, (anonymous namespace)::EqIsZeroJumpI, (anonymous namespace)::DoubleJump, (anonymous namespace)::JumpToNext, (anonymous namespace)::UnreachableCode, (anonymous namespace)::TagConjunctions, (anonymous namespace)::TruthyAnd, (anonymous namespace)::Identity) Line | Count | Source | 471 | 19.1M | { | 472 | 19.1M | if (!Method::apply(_state)) | 473 | 19.1M | applyMethods(_state, _other...); | 474 | 19.1M | } |
PeepholeOptimiser.cpp:void (anonymous namespace)::applyMethods<(anonymous namespace)::OpPop, (anonymous namespace)::OpStop, (anonymous namespace)::OpReturnRevert, (anonymous namespace)::DoublePush, (anonymous namespace)::DoubleSwap, (anonymous namespace)::CommutativeSwap, (anonymous namespace)::SwapComparison, (anonymous namespace)::DupSwap, (anonymous namespace)::IsZeroIsZeroJumpI, (anonymous namespace)::EqIsZeroJumpI, (anonymous namespace)::DoubleJump, (anonymous namespace)::JumpToNext, (anonymous namespace)::UnreachableCode, (anonymous namespace)::TagConjunctions, (anonymous namespace)::TruthyAnd, (anonymous namespace)::Identity>((anonymous namespace)::OptimiserState&, (anonymous namespace)::OpPop, (anonymous namespace)::OpStop, (anonymous namespace)::OpReturnRevert, (anonymous namespace)::DoublePush, (anonymous namespace)::DoubleSwap, (anonymous namespace)::CommutativeSwap, (anonymous namespace)::SwapComparison, (anonymous namespace)::DupSwap, (anonymous namespace)::IsZeroIsZeroJumpI, (anonymous namespace)::EqIsZeroJumpI, (anonymous namespace)::DoubleJump, (anonymous namespace)::JumpToNext, (anonymous namespace)::UnreachableCode, (anonymous namespace)::TagConjunctions, (anonymous namespace)::TruthyAnd, (anonymous namespace)::Identity) Line | Count | Source | 471 | 19.1M | { | 472 | 19.1M | if (!Method::apply(_state)) | 473 | 19.1M | applyMethods(_state, _other...); | 474 | 19.1M | } |
PeepholeOptimiser.cpp:void (anonymous namespace)::applyMethods<(anonymous namespace)::OpStop, (anonymous namespace)::OpReturnRevert, (anonymous namespace)::DoublePush, (anonymous namespace)::DoubleSwap, (anonymous namespace)::CommutativeSwap, (anonymous namespace)::SwapComparison, (anonymous namespace)::DupSwap, (anonymous namespace)::IsZeroIsZeroJumpI, (anonymous namespace)::EqIsZeroJumpI, (anonymous namespace)::DoubleJump, (anonymous namespace)::JumpToNext, (anonymous namespace)::UnreachableCode, (anonymous namespace)::TagConjunctions, (anonymous namespace)::TruthyAnd, (anonymous namespace)::Identity>((anonymous namespace)::OptimiserState&, (anonymous namespace)::OpStop, (anonymous namespace)::OpReturnRevert, (anonymous namespace)::DoublePush, (anonymous namespace)::DoubleSwap, (anonymous namespace)::CommutativeSwap, (anonymous namespace)::SwapComparison, (anonymous namespace)::DupSwap, (anonymous namespace)::IsZeroIsZeroJumpI, (anonymous namespace)::EqIsZeroJumpI, (anonymous namespace)::DoubleJump, (anonymous namespace)::JumpToNext, (anonymous namespace)::UnreachableCode, (anonymous namespace)::TagConjunctions, (anonymous namespace)::TruthyAnd, (anonymous namespace)::Identity) Line | Count | Source | 471 | 19.1M | { | 472 | 19.1M | if (!Method::apply(_state)) | 473 | 19.1M | applyMethods(_state, _other...); | 474 | 19.1M | } |
PeepholeOptimiser.cpp:void (anonymous namespace)::applyMethods<(anonymous namespace)::OpReturnRevert, (anonymous namespace)::DoublePush, (anonymous namespace)::DoubleSwap, (anonymous namespace)::CommutativeSwap, (anonymous namespace)::SwapComparison, (anonymous namespace)::DupSwap, (anonymous namespace)::IsZeroIsZeroJumpI, (anonymous namespace)::EqIsZeroJumpI, (anonymous namespace)::DoubleJump, (anonymous namespace)::JumpToNext, (anonymous namespace)::UnreachableCode, (anonymous namespace)::TagConjunctions, (anonymous namespace)::TruthyAnd, (anonymous namespace)::Identity>((anonymous namespace)::OptimiserState&, (anonymous namespace)::OpReturnRevert, (anonymous namespace)::DoublePush, (anonymous namespace)::DoubleSwap, (anonymous namespace)::CommutativeSwap, (anonymous namespace)::SwapComparison, (anonymous namespace)::DupSwap, (anonymous namespace)::IsZeroIsZeroJumpI, (anonymous namespace)::EqIsZeroJumpI, (anonymous namespace)::DoubleJump, (anonymous namespace)::JumpToNext, (anonymous namespace)::UnreachableCode, (anonymous namespace)::TagConjunctions, (anonymous namespace)::TruthyAnd, (anonymous namespace)::Identity) Line | Count | Source | 471 | 19.1M | { | 472 | 19.1M | if (!Method::apply(_state)) | 473 | 19.1M | applyMethods(_state, _other...); | 474 | 19.1M | } |
PeepholeOptimiser.cpp:void (anonymous namespace)::applyMethods<(anonymous namespace)::DoublePush, (anonymous namespace)::DoubleSwap, (anonymous namespace)::CommutativeSwap, (anonymous namespace)::SwapComparison, (anonymous namespace)::DupSwap, (anonymous namespace)::IsZeroIsZeroJumpI, (anonymous namespace)::EqIsZeroJumpI, (anonymous namespace)::DoubleJump, (anonymous namespace)::JumpToNext, (anonymous namespace)::UnreachableCode, (anonymous namespace)::TagConjunctions, (anonymous namespace)::TruthyAnd, (anonymous namespace)::Identity>((anonymous namespace)::OptimiserState&, (anonymous namespace)::DoublePush, (anonymous namespace)::DoubleSwap, (anonymous namespace)::CommutativeSwap, (anonymous namespace)::SwapComparison, (anonymous namespace)::DupSwap, (anonymous namespace)::IsZeroIsZeroJumpI, (anonymous namespace)::EqIsZeroJumpI, (anonymous namespace)::DoubleJump, (anonymous namespace)::JumpToNext, (anonymous namespace)::UnreachableCode, (anonymous namespace)::TagConjunctions, (anonymous namespace)::TruthyAnd, (anonymous namespace)::Identity) Line | Count | Source | 471 | 19.1M | { | 472 | 19.1M | if (!Method::apply(_state)) | 473 | 19.0M | applyMethods(_state, _other...); | 474 | 19.1M | } |
PeepholeOptimiser.cpp:void (anonymous namespace)::applyMethods<(anonymous namespace)::DoubleSwap, (anonymous namespace)::CommutativeSwap, (anonymous namespace)::SwapComparison, (anonymous namespace)::DupSwap, (anonymous namespace)::IsZeroIsZeroJumpI, (anonymous namespace)::EqIsZeroJumpI, (anonymous namespace)::DoubleJump, (anonymous namespace)::JumpToNext, (anonymous namespace)::UnreachableCode, (anonymous namespace)::TagConjunctions, (anonymous namespace)::TruthyAnd, (anonymous namespace)::Identity>((anonymous namespace)::OptimiserState&, (anonymous namespace)::DoubleSwap, (anonymous namespace)::CommutativeSwap, (anonymous namespace)::SwapComparison, (anonymous namespace)::DupSwap, (anonymous namespace)::IsZeroIsZeroJumpI, (anonymous namespace)::EqIsZeroJumpI, (anonymous namespace)::DoubleJump, (anonymous namespace)::JumpToNext, (anonymous namespace)::UnreachableCode, (anonymous namespace)::TagConjunctions, (anonymous namespace)::TruthyAnd, (anonymous namespace)::Identity) Line | Count | Source | 471 | 19.0M | { | 472 | 19.0M | if (!Method::apply(_state)) | 473 | 19.0M | applyMethods(_state, _other...); | 474 | 19.0M | } |
PeepholeOptimiser.cpp:void (anonymous namespace)::applyMethods<(anonymous namespace)::CommutativeSwap, (anonymous namespace)::SwapComparison, (anonymous namespace)::DupSwap, (anonymous namespace)::IsZeroIsZeroJumpI, (anonymous namespace)::EqIsZeroJumpI, (anonymous namespace)::DoubleJump, (anonymous namespace)::JumpToNext, (anonymous namespace)::UnreachableCode, (anonymous namespace)::TagConjunctions, (anonymous namespace)::TruthyAnd, (anonymous namespace)::Identity>((anonymous namespace)::OptimiserState&, (anonymous namespace)::CommutativeSwap, (anonymous namespace)::SwapComparison, (anonymous namespace)::DupSwap, (anonymous namespace)::IsZeroIsZeroJumpI, (anonymous namespace)::EqIsZeroJumpI, (anonymous namespace)::DoubleJump, (anonymous namespace)::JumpToNext, (anonymous namespace)::UnreachableCode, (anonymous namespace)::TagConjunctions, (anonymous namespace)::TruthyAnd, (anonymous namespace)::Identity) Line | Count | Source | 471 | 19.0M | { | 472 | 19.0M | if (!Method::apply(_state)) | 473 | 19.0M | applyMethods(_state, _other...); | 474 | 19.0M | } |
PeepholeOptimiser.cpp:void (anonymous namespace)::applyMethods<(anonymous namespace)::SwapComparison, (anonymous namespace)::DupSwap, (anonymous namespace)::IsZeroIsZeroJumpI, (anonymous namespace)::EqIsZeroJumpI, (anonymous namespace)::DoubleJump, (anonymous namespace)::JumpToNext, (anonymous namespace)::UnreachableCode, (anonymous namespace)::TagConjunctions, (anonymous namespace)::TruthyAnd, (anonymous namespace)::Identity>((anonymous namespace)::OptimiserState&, (anonymous namespace)::SwapComparison, (anonymous namespace)::DupSwap, (anonymous namespace)::IsZeroIsZeroJumpI, (anonymous namespace)::EqIsZeroJumpI, (anonymous namespace)::DoubleJump, (anonymous namespace)::JumpToNext, (anonymous namespace)::UnreachableCode, (anonymous namespace)::TagConjunctions, (anonymous namespace)::TruthyAnd, (anonymous namespace)::Identity) Line | Count | Source | 471 | 19.0M | { | 472 | 19.0M | if (!Method::apply(_state)) | 473 | 19.0M | applyMethods(_state, _other...); | 474 | 19.0M | } |
PeepholeOptimiser.cpp:void (anonymous namespace)::applyMethods<(anonymous namespace)::DupSwap, (anonymous namespace)::IsZeroIsZeroJumpI, (anonymous namespace)::EqIsZeroJumpI, (anonymous namespace)::DoubleJump, (anonymous namespace)::JumpToNext, (anonymous namespace)::UnreachableCode, (anonymous namespace)::TagConjunctions, (anonymous namespace)::TruthyAnd, (anonymous namespace)::Identity>((anonymous namespace)::OptimiserState&, (anonymous namespace)::DupSwap, (anonymous namespace)::IsZeroIsZeroJumpI, (anonymous namespace)::EqIsZeroJumpI, (anonymous namespace)::DoubleJump, (anonymous namespace)::JumpToNext, (anonymous namespace)::UnreachableCode, (anonymous namespace)::TagConjunctions, (anonymous namespace)::TruthyAnd, (anonymous namespace)::Identity) Line | Count | Source | 471 | 19.0M | { | 472 | 19.0M | if (!Method::apply(_state)) | 473 | 19.0M | applyMethods(_state, _other...); | 474 | 19.0M | } |
PeepholeOptimiser.cpp:void (anonymous namespace)::applyMethods<(anonymous namespace)::IsZeroIsZeroJumpI, (anonymous namespace)::EqIsZeroJumpI, (anonymous namespace)::DoubleJump, (anonymous namespace)::JumpToNext, (anonymous namespace)::UnreachableCode, (anonymous namespace)::TagConjunctions, (anonymous namespace)::TruthyAnd, (anonymous namespace)::Identity>((anonymous namespace)::OptimiserState&, (anonymous namespace)::IsZeroIsZeroJumpI, (anonymous namespace)::EqIsZeroJumpI, (anonymous namespace)::DoubleJump, (anonymous namespace)::JumpToNext, (anonymous namespace)::UnreachableCode, (anonymous namespace)::TagConjunctions, (anonymous namespace)::TruthyAnd, (anonymous namespace)::Identity) Line | Count | Source | 471 | 19.0M | { | 472 | 19.0M | if (!Method::apply(_state)) | 473 | 19.0M | applyMethods(_state, _other...); | 474 | 19.0M | } |
PeepholeOptimiser.cpp:void (anonymous namespace)::applyMethods<(anonymous namespace)::EqIsZeroJumpI, (anonymous namespace)::DoubleJump, (anonymous namespace)::JumpToNext, (anonymous namespace)::UnreachableCode, (anonymous namespace)::TagConjunctions, (anonymous namespace)::TruthyAnd, (anonymous namespace)::Identity>((anonymous namespace)::OptimiserState&, (anonymous namespace)::EqIsZeroJumpI, (anonymous namespace)::DoubleJump, (anonymous namespace)::JumpToNext, (anonymous namespace)::UnreachableCode, (anonymous namespace)::TagConjunctions, (anonymous namespace)::TruthyAnd, (anonymous namespace)::Identity) Line | Count | Source | 471 | 19.0M | { | 472 | 19.0M | if (!Method::apply(_state)) | 473 | 19.0M | applyMethods(_state, _other...); | 474 | 19.0M | } |
PeepholeOptimiser.cpp:void (anonymous namespace)::applyMethods<(anonymous namespace)::DoubleJump, (anonymous namespace)::JumpToNext, (anonymous namespace)::UnreachableCode, (anonymous namespace)::TagConjunctions, (anonymous namespace)::TruthyAnd, (anonymous namespace)::Identity>((anonymous namespace)::OptimiserState&, (anonymous namespace)::DoubleJump, (anonymous namespace)::JumpToNext, (anonymous namespace)::UnreachableCode, (anonymous namespace)::TagConjunctions, (anonymous namespace)::TruthyAnd, (anonymous namespace)::Identity) Line | Count | Source | 471 | 19.0M | { | 472 | 19.0M | if (!Method::apply(_state)) | 473 | 19.0M | applyMethods(_state, _other...); | 474 | 19.0M | } |
PeepholeOptimiser.cpp:void (anonymous namespace)::applyMethods<(anonymous namespace)::JumpToNext, (anonymous namespace)::UnreachableCode, (anonymous namespace)::TagConjunctions, (anonymous namespace)::TruthyAnd, (anonymous namespace)::Identity>((anonymous namespace)::OptimiserState&, (anonymous namespace)::JumpToNext, (anonymous namespace)::UnreachableCode, (anonymous namespace)::TagConjunctions, (anonymous namespace)::TruthyAnd, (anonymous namespace)::Identity) Line | Count | Source | 471 | 19.0M | { | 472 | 19.0M | if (!Method::apply(_state)) | 473 | 19.0M | applyMethods(_state, _other...); | 474 | 19.0M | } |
PeepholeOptimiser.cpp:void (anonymous namespace)::applyMethods<(anonymous namespace)::UnreachableCode, (anonymous namespace)::TagConjunctions, (anonymous namespace)::TruthyAnd, (anonymous namespace)::Identity>((anonymous namespace)::OptimiserState&, (anonymous namespace)::UnreachableCode, (anonymous namespace)::TagConjunctions, (anonymous namespace)::TruthyAnd, (anonymous namespace)::Identity) Line | Count | Source | 471 | 19.0M | { | 472 | 19.0M | if (!Method::apply(_state)) | 473 | 19.0M | applyMethods(_state, _other...); | 474 | 19.0M | } |
PeepholeOptimiser.cpp:void (anonymous namespace)::applyMethods<(anonymous namespace)::TagConjunctions, (anonymous namespace)::TruthyAnd, (anonymous namespace)::Identity>((anonymous namespace)::OptimiserState&, (anonymous namespace)::TagConjunctions, (anonymous namespace)::TruthyAnd, (anonymous namespace)::Identity) Line | Count | Source | 471 | 19.0M | { | 472 | 19.0M | if (!Method::apply(_state)) | 473 | 19.0M | applyMethods(_state, _other...); | 474 | 19.0M | } |
PeepholeOptimiser.cpp:void (anonymous namespace)::applyMethods<(anonymous namespace)::TruthyAnd, (anonymous namespace)::Identity>((anonymous namespace)::OptimiserState&, (anonymous namespace)::TruthyAnd, (anonymous namespace)::Identity) Line | Count | Source | 471 | 19.0M | { | 472 | 19.0M | if (!Method::apply(_state)) | 473 | 19.0M | applyMethods(_state, _other...); | 474 | 19.0M | } |
PeepholeOptimiser.cpp:void (anonymous namespace)::applyMethods<(anonymous namespace)::Identity>((anonymous namespace)::OptimiserState&, (anonymous namespace)::Identity) Line | Count | Source | 471 | 19.0M | { | 472 | 19.0M | if (!Method::apply(_state)) | 473 | 0 | applyMethods(_state, _other...); | 474 | 19.0M | } |
|
475 | | |
476 | | size_t numberOfPops(AssemblyItems const& _items) |
477 | 51.3k | { |
478 | 51.3k | return static_cast<size_t>(std::count(_items.begin(), _items.end(), Instruction::POP)); |
479 | 51.3k | } |
480 | | |
481 | | } |
482 | | |
483 | | bool PeepholeOptimiser::optimise() |
484 | 54.5k | { |
485 | | // Avoid referencing immutables too early by using approx. counting in bytesRequired() |
486 | 54.5k | auto const approx = evmasm::Precision::Approximate; |
487 | 54.5k | OptimiserState state {m_items, 0, std::back_inserter(m_optimisedItems)}; |
488 | 19.2M | while (state.i < m_items.size()) |
489 | 19.1M | applyMethods( |
490 | 19.1M | state, |
491 | 19.1M | PushPop(), OpPop(), OpStop(), OpReturnRevert(), DoublePush(), DoubleSwap(), CommutativeSwap(), SwapComparison(), |
492 | 19.1M | DupSwap(), IsZeroIsZeroJumpI(), EqIsZeroJumpI(), DoubleJump(), JumpToNext(), UnreachableCode(), |
493 | 19.1M | TagConjunctions(), TruthyAnd(), Identity() |
494 | 19.1M | ); |
495 | 54.5k | if (m_optimisedItems.size() < m_items.size() || ( |
496 | 26.5k | m_optimisedItems.size() == m_items.size() && ( |
497 | 26.4k | evmasm::bytesRequired(m_optimisedItems, 3, approx) < evmasm::bytesRequired(m_items, 3, approx) || |
498 | 26.4k | numberOfPops(m_optimisedItems) > numberOfPops(m_items) |
499 | 26.4k | ) |
500 | 26.5k | )) |
501 | 30.9k | { |
502 | 30.9k | m_items = std::move(m_optimisedItems); |
503 | 30.9k | return true; |
504 | 30.9k | } |
505 | 23.6k | else |
506 | 23.6k | return false; |
507 | 54.5k | } |