Coverage Report

Created: 2022-08-24 06:32

/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
232M
  {
58
232M
    return Method::applySimple(_in[Indices]..., _out);
59
232M
  }
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
14.6M
  {
58
14.6M
    return Method::applySimple(_in[Indices]..., _out);
59
14.6M
  }
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
14.6M
  {
58
14.6M
    return Method::applySimple(_in[Indices]..., _out);
59
14.6M
  }
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
14.6M
  {
58
14.6M
    return Method::applySimple(_in[Indices]..., _out);
59
14.6M
  }
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
14.4M
  {
58
14.4M
    return Method::applySimple(_in[Indices]..., _out);
59
14.4M
  }
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
14.5M
  {
58
14.5M
    return Method::applySimple(_in[Indices]..., _out);
59
14.5M
  }
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
14.5M
  {
58
14.5M
    return Method::applySimple(_in[Indices]..., _out);
59
14.5M
  }
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
14.5M
  {
58
14.5M
    return Method::applySimple(_in[Indices]..., _out);
59
14.5M
  }
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
14.5M
  {
58
14.5M
    return Method::applySimple(_in[Indices]..., _out);
59
14.5M
  }
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
14.5M
  {
58
14.5M
    return Method::applySimple(_in[Indices]..., _out);
59
14.5M
  }
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
14.4M
  {
58
14.4M
    return Method::applySimple(_in[Indices]..., _out);
59
14.4M
  }
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
14.4M
  {
58
14.4M
    return Method::applySimple(_in[Indices]..., _out);
59
14.4M
  }
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
14.3M
  {
58
14.3M
    return Method::applySimple(_in[Indices]..., _out);
59
14.3M
  }
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
14.5M
  {
58
14.5M
    return Method::applySimple(_in[Indices]..., _out);
59
14.5M
  }
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
14.4M
  {
58
14.4M
    return Method::applySimple(_in[Indices]..., _out);
59
14.4M
  }
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
14.4M
  {
58
14.4M
    return Method::applySimple(_in[Indices]..., _out);
59
14.4M
  }
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
14.6M
  {
58
14.6M
    return Method::applySimple(_in[Indices]..., _out);
59
14.6M
  }
60
  static bool apply(OptimiserState& _state)
61
234M
  {
62
234M
    static constexpr size_t WindowSize = FunctionParameterCount<decltype(Method::applySimple)>::value - 1;
63
234M
    if (
64
234M
      _state.i + WindowSize <= _state.items.size() &&
65
234M
      applyRule(_state.items.begin() + static_cast<ptrdiff_t>(_state.i), _state.out, make_index_sequence<WindowSize>{})
66
234M
    )
67
14.6M
    {
68
14.6M
      _state.i += WindowSize;
69
14.6M
      return true;
70
14.6M
    }
71
220M
    else
72
220M
      return false;
73
234M
  }
PeepholeOptimiser.cpp:(anonymous namespace)::SimplePeepholeOptimizerMethod<(anonymous namespace)::PushPop>::apply((anonymous namespace)::OptimiserState&)
Line
Count
Source
61
14.7M
  {
62
14.7M
    static constexpr size_t WindowSize = FunctionParameterCount<decltype(Method::applySimple)>::value - 1;
63
14.7M
    if (
64
14.7M
      _state.i + WindowSize <= _state.items.size() &&
65
14.7M
      applyRule(_state.items.begin() + static_cast<ptrdiff_t>(_state.i), _state.out, make_index_sequence<WindowSize>{})
66
14.7M
    )
67
16.9k
    {
68
16.9k
      _state.i += WindowSize;
69
16.9k
      return true;
70
16.9k
    }
71
14.7M
    else
72
14.7M
      return false;
73
14.7M
  }
PeepholeOptimiser.cpp:(anonymous namespace)::SimplePeepholeOptimizerMethod<(anonymous namespace)::OpPop>::apply((anonymous namespace)::OptimiserState&)
Line
Count
Source
61
14.7M
  {
62
14.7M
    static constexpr size_t WindowSize = FunctionParameterCount<decltype(Method::applySimple)>::value - 1;
63
14.7M
    if (
64
14.7M
      _state.i + WindowSize <= _state.items.size() &&
65
14.7M
      applyRule(_state.items.begin() + static_cast<ptrdiff_t>(_state.i), _state.out, make_index_sequence<WindowSize>{})
66
14.7M
    )
67
2.30k
    {
68
2.30k
      _state.i += WindowSize;
69
2.30k
      return true;
70
2.30k
    }
71
14.7M
    else
72
14.7M
      return false;
73
14.7M
  }
PeepholeOptimiser.cpp:(anonymous namespace)::SimplePeepholeOptimizerMethod<(anonymous namespace)::OpStop>::apply((anonymous namespace)::OptimiserState&)
Line
Count
Source
61
14.7M
  {
62
14.7M
    static constexpr size_t WindowSize = FunctionParameterCount<decltype(Method::applySimple)>::value - 1;
63
14.7M
    if (
64
14.7M
      _state.i + WindowSize <= _state.items.size() &&
65
14.7M
      applyRule(_state.items.begin() + static_cast<ptrdiff_t>(_state.i), _state.out, make_index_sequence<WindowSize>{})
66
14.7M
    )
67
7.87k
    {
68
7.87k
      _state.i += WindowSize;
69
7.87k
      return true;
70
7.87k
    }
71
14.6M
    else
72
14.6M
      return false;
73
14.7M
  }
PeepholeOptimiser.cpp:(anonymous namespace)::SimplePeepholeOptimizerMethod<(anonymous namespace)::OpReturnRevert>::apply((anonymous namespace)::OptimiserState&)
Line
Count
Source
61
14.6M
  {
62
14.6M
    static constexpr size_t WindowSize = FunctionParameterCount<decltype(Method::applySimple)>::value - 1;
63
14.6M
    if (
64
14.6M
      _state.i + WindowSize <= _state.items.size() &&
65
14.6M
      applyRule(_state.items.begin() + static_cast<ptrdiff_t>(_state.i), _state.out, make_index_sequence<WindowSize>{})
66
14.6M
    )
67
152
    {
68
152
      _state.i += WindowSize;
69
152
      return true;
70
152
    }
71
14.6M
    else
72
14.6M
      return false;
73
14.6M
  }
PeepholeOptimiser.cpp:(anonymous namespace)::SimplePeepholeOptimizerMethod<(anonymous namespace)::DoublePush>::apply((anonymous namespace)::OptimiserState&)
Line
Count
Source
61
14.6M
  {
62
14.6M
    static constexpr size_t WindowSize = FunctionParameterCount<decltype(Method::applySimple)>::value - 1;
63
14.6M
    if (
64
14.6M
      _state.i + WindowSize <= _state.items.size() &&
65
14.6M
      applyRule(_state.items.begin() + static_cast<ptrdiff_t>(_state.i), _state.out, make_index_sequence<WindowSize>{})
66
14.6M
    )
67
1.58k
    {
68
1.58k
      _state.i += WindowSize;
69
1.58k
      return true;
70
1.58k
    }
71
14.6M
    else
72
14.6M
      return false;
73
14.6M
  }
PeepholeOptimiser.cpp:(anonymous namespace)::SimplePeepholeOptimizerMethod<(anonymous namespace)::DoubleSwap>::apply((anonymous namespace)::OptimiserState&)
Line
Count
Source
61
14.6M
  {
62
14.6M
    static constexpr size_t WindowSize = FunctionParameterCount<decltype(Method::applySimple)>::value - 1;
63
14.6M
    if (
64
14.6M
      _state.i + WindowSize <= _state.items.size() &&
65
14.6M
      applyRule(_state.items.begin() + static_cast<ptrdiff_t>(_state.i), _state.out, make_index_sequence<WindowSize>{})
66
14.6M
    )
67
730
    {
68
730
      _state.i += WindowSize;
69
730
      return true;
70
730
    }
71
14.6M
    else
72
14.6M
      return false;
73
14.6M
  }
PeepholeOptimiser.cpp:(anonymous namespace)::SimplePeepholeOptimizerMethod<(anonymous namespace)::CommutativeSwap>::apply((anonymous namespace)::OptimiserState&)
Line
Count
Source
61
14.6M
  {
62
14.6M
    static constexpr size_t WindowSize = FunctionParameterCount<decltype(Method::applySimple)>::value - 1;
63
14.6M
    if (
64
14.6M
      _state.i + WindowSize <= _state.items.size() &&
65
14.6M
      applyRule(_state.items.begin() + static_cast<ptrdiff_t>(_state.i), _state.out, make_index_sequence<WindowSize>{})
66
14.6M
    )
67
155
    {
68
155
      _state.i += WindowSize;
69
155
      return true;
70
155
    }
71
14.6M
    else
72
14.6M
      return false;
73
14.6M
  }
PeepholeOptimiser.cpp:(anonymous namespace)::SimplePeepholeOptimizerMethod<(anonymous namespace)::SwapComparison>::apply((anonymous namespace)::OptimiserState&)
Line
Count
Source
61
14.6M
  {
62
14.6M
    static constexpr size_t WindowSize = FunctionParameterCount<decltype(Method::applySimple)>::value - 1;
63
14.6M
    if (
64
14.6M
      _state.i + WindowSize <= _state.items.size() &&
65
14.6M
      applyRule(_state.items.begin() + static_cast<ptrdiff_t>(_state.i), _state.out, make_index_sequence<WindowSize>{})
66
14.6M
    )
67
1.34k
    {
68
1.34k
      _state.i += WindowSize;
69
1.34k
      return true;
70
1.34k
    }
71
14.6M
    else
72
14.6M
      return false;
73
14.6M
  }
PeepholeOptimiser.cpp:(anonymous namespace)::SimplePeepholeOptimizerMethod<(anonymous namespace)::DupSwap>::apply((anonymous namespace)::OptimiserState&)
Line
Count
Source
61
14.6M
  {
62
14.6M
    static constexpr size_t WindowSize = FunctionParameterCount<decltype(Method::applySimple)>::value - 1;
63
14.6M
    if (
64
14.6M
      _state.i + WindowSize <= _state.items.size() &&
65
14.6M
      applyRule(_state.items.begin() + static_cast<ptrdiff_t>(_state.i), _state.out, make_index_sequence<WindowSize>{})
66
14.6M
    )
67
1.64k
    {
68
1.64k
      _state.i += WindowSize;
69
1.64k
      return true;
70
1.64k
    }
71
14.6M
    else
72
14.6M
      return false;
73
14.6M
  }
PeepholeOptimiser.cpp:(anonymous namespace)::SimplePeepholeOptimizerMethod<(anonymous namespace)::IsZeroIsZeroJumpI>::apply((anonymous namespace)::OptimiserState&)
Line
Count
Source
61
14.6M
  {
62
14.6M
    static constexpr size_t WindowSize = FunctionParameterCount<decltype(Method::applySimple)>::value - 1;
63
14.6M
    if (
64
14.6M
      _state.i + WindowSize <= _state.items.size() &&
65
14.6M
      applyRule(_state.items.begin() + static_cast<ptrdiff_t>(_state.i), _state.out, make_index_sequence<WindowSize>{})
66
14.6M
    )
67
16
    {
68
16
      _state.i += WindowSize;
69
16
      return true;
70
16
    }
71
14.6M
    else
72
14.6M
      return false;
73
14.6M
  }
PeepholeOptimiser.cpp:(anonymous namespace)::SimplePeepholeOptimizerMethod<(anonymous namespace)::EqIsZeroJumpI>::apply((anonymous namespace)::OptimiserState&)
Line
Count
Source
61
14.6M
  {
62
14.6M
    static constexpr size_t WindowSize = FunctionParameterCount<decltype(Method::applySimple)>::value - 1;
63
14.6M
    if (
64
14.6M
      _state.i + WindowSize <= _state.items.size() &&
65
14.6M
      applyRule(_state.items.begin() + static_cast<ptrdiff_t>(_state.i), _state.out, make_index_sequence<WindowSize>{})
66
14.6M
    )
67
52
    {
68
52
      _state.i += WindowSize;
69
52
      return true;
70
52
    }
71
14.6M
    else
72
14.6M
      return false;
73
14.6M
  }
PeepholeOptimiser.cpp:(anonymous namespace)::SimplePeepholeOptimizerMethod<(anonymous namespace)::DoubleJump>::apply((anonymous namespace)::OptimiserState&)
Line
Count
Source
61
14.6M
  {
62
14.6M
    static constexpr size_t WindowSize = FunctionParameterCount<decltype(Method::applySimple)>::value - 1;
63
14.6M
    if (
64
14.6M
      _state.i + WindowSize <= _state.items.size() &&
65
14.6M
      applyRule(_state.items.begin() + static_cast<ptrdiff_t>(_state.i), _state.out, make_index_sequence<WindowSize>{})
66
14.6M
    )
67
1.14k
    {
68
1.14k
      _state.i += WindowSize;
69
1.14k
      return true;
70
1.14k
    }
71
14.6M
    else
72
14.6M
      return false;
73
14.6M
  }
PeepholeOptimiser.cpp:(anonymous namespace)::SimplePeepholeOptimizerMethod<(anonymous namespace)::JumpToNext>::apply((anonymous namespace)::OptimiserState&)
Line
Count
Source
61
14.6M
  {
62
14.6M
    static constexpr size_t WindowSize = FunctionParameterCount<decltype(Method::applySimple)>::value - 1;
63
14.6M
    if (
64
14.6M
      _state.i + WindowSize <= _state.items.size() &&
65
14.6M
      applyRule(_state.items.begin() + static_cast<ptrdiff_t>(_state.i), _state.out, make_index_sequence<WindowSize>{})
66
14.6M
    )
67
23.2k
    {
68
23.2k
      _state.i += WindowSize;
69
23.2k
      return true;
70
23.2k
    }
71
14.6M
    else
72
14.6M
      return false;
73
14.6M
  }
PeepholeOptimiser.cpp:(anonymous namespace)::SimplePeepholeOptimizerMethod<(anonymous namespace)::TagConjunctions>::apply((anonymous namespace)::OptimiserState&)
Line
Count
Source
61
14.6M
  {
62
14.6M
    static constexpr size_t WindowSize = FunctionParameterCount<decltype(Method::applySimple)>::value - 1;
63
14.6M
    if (
64
14.6M
      _state.i + WindowSize <= _state.items.size() &&
65
14.6M
      applyRule(_state.items.begin() + static_cast<ptrdiff_t>(_state.i), _state.out, make_index_sequence<WindowSize>{})
66
14.6M
    )
67
0
    {
68
0
      _state.i += WindowSize;
69
0
      return true;
70
0
    }
71
14.6M
    else
72
14.6M
      return false;
73
14.6M
  }
PeepholeOptimiser.cpp:(anonymous namespace)::SimplePeepholeOptimizerMethod<(anonymous namespace)::TruthyAnd>::apply((anonymous namespace)::OptimiserState&)
Line
Count
Source
61
14.6M
  {
62
14.6M
    static constexpr size_t WindowSize = FunctionParameterCount<decltype(Method::applySimple)>::value - 1;
63
14.6M
    if (
64
14.6M
      _state.i + WindowSize <= _state.items.size() &&
65
14.6M
      applyRule(_state.items.begin() + static_cast<ptrdiff_t>(_state.i), _state.out, make_index_sequence<WindowSize>{})
66
14.6M
    )
67
3
    {
68
3
      _state.i += WindowSize;
69
3
      return true;
70
3
    }
71
14.6M
    else
72
14.6M
      return false;
73
14.6M
  }
PeepholeOptimiser.cpp:(anonymous namespace)::SimplePeepholeOptimizerMethod<(anonymous namespace)::Identity>::apply((anonymous namespace)::OptimiserState&)
Line
Count
Source
61
14.6M
  {
62
14.6M
    static constexpr size_t WindowSize = FunctionParameterCount<decltype(Method::applySimple)>::value - 1;
63
14.6M
    if (
64
14.6M
      _state.i + WindowSize <= _state.items.size() &&
65
14.6M
      applyRule(_state.items.begin() + static_cast<ptrdiff_t>(_state.i), _state.out, make_index_sequence<WindowSize>{})
66
14.6M
    )
67
14.6M
    {
68
14.6M
      _state.i += WindowSize;
69
14.6M
      return true;
70
14.6M
    }
71
0
    else
72
0
      return false;
73
14.6M
  }
74
};
75
76
struct Identity: SimplePeepholeOptimizerMethod<Identity>
77
{
78
  static bool applySimple(AssemblyItem const& _item, std::back_insert_iterator<AssemblyItems> _out)
79
14.6M
  {
80
14.6M
    *_out = _item;
81
14.6M
    return true;
82
14.6M
  }
83
};
84
85
struct PushPop: SimplePeepholeOptimizerMethod<PushPop>
86
{
87
  static bool applySimple(AssemblyItem const& _push, AssemblyItem const& _pop, std::back_insert_iterator<AssemblyItems>)
88
14.6M
  {
89
14.6M
    auto t = _push.type();
90
14.6M
    return _pop == Instruction::POP && (
91
338k
      SemanticInformation::isDupInstruction(_push) ||
92
338k
      t == Push || t == PushTag || t == PushSub ||
93
338k
      t == PushSubSize || t == PushProgramSize || t == PushData || t == PushLibraryAddress
94
338k
    );
95
14.6M
  }
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
14.6M
  {
106
14.6M
    if (_pop == Instruction::POP && _op.type() == Operation)
107
308k
    {
108
308k
      Instruction instr = _op.instruction();
109
308k
      if (instructionInfo(instr).ret == 1 && !instructionInfo(instr).sideEffects)
110
2.30k
      {
111
6.78k
        for (int j = 0; j < instructionInfo(instr).args; j++)
112
4.48k
          *_out = {Instruction::POP, _op.location()};
113
2.30k
        return true;
114
2.30k
      }
115
308k
    }
116
14.6M
    return false;
117
14.6M
  }
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
14.6M
  {
128
14.6M
    if (_stop == Instruction::STOP)
129
117k
    {
130
117k
      if (_op.type() == Operation)
131
61.4k
      {
132
61.4k
        Instruction instr = _op.instruction();
133
61.4k
        if (!instructionInfo(instr).sideEffects)
134
6.71k
        {
135
6.71k
          *_out = {Instruction::STOP, _op.location()};
136
6.71k
          return true;
137
6.71k
        }
138
61.4k
      }
139
55.9k
      else if (_op.type() == Push)
140
1.16k
      {
141
1.16k
        *_out = {Instruction::STOP, _op.location()};
142
1.16k
        return true;
143
1.16k
      }
144
117k
    }
145
14.5M
    return false;
146
14.6M
  }
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
14.4M
  {
159
14.4M
    if (
160
14.4M
      (_returnRevert == Instruction::RETURN || _returnRevert == Instruction::REVERT) &&
161
14.4M
      _push.type() == Push &&
162
14.4M
      (_pushOrDup.type() == Push || _pushOrDup == dupInstruction(1))
163
14.4M
    )
164
1.44k
      if (
165
1.44k
        (_op.type() == Operation && !instructionInfo(_op.instruction()).sideEffects) ||
166
1.44k
        _op.type() == Push
167
1.44k
      )
168
152
      {
169
152
          *_out = _push;
170
152
          *_out = _pushOrDup;
171
152
          *_out = _returnRevert;
172
152
          return true;
173
152
      }
174
14.4M
    return false;
175
14.4M
  }
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
14.5M
  {
182
14.5M
    return _s1 == _s2 && SemanticInformation::isSwapInstruction(_s1);
183
14.5M
  }
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
14.5M
  {
190
14.5M
    if (_push1.type() == Push && _push2.type() == Push && _push1.data() == _push2.data())
191
1.58k
    {
192
1.58k
      *_out = _push1;
193
1.58k
      *_out = {Instruction::DUP1, _push2.location()};
194
1.58k
      return true;
195
1.58k
    }
196
14.5M
    else
197
14.5M
      return false;
198
14.5M
  }
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
14.5M
  {
205
    // Remove SWAP1 if following instruction is commutative
206
14.5M
    if (
207
14.5M
      _swap == Instruction::SWAP1 &&
208
14.5M
      SemanticInformation::isCommutativeOperation(_op)
209
14.5M
    )
210
155
    {
211
155
      *_out = _op;
212
155
      return true;
213
155
    }
214
14.5M
    else
215
14.5M
      return false;
216
14.5M
  }
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
14.5M
  {
223
14.5M
    static map<Instruction, Instruction> const swappableOps{
224
14.5M
      { Instruction::LT, Instruction::GT },
225
14.5M
      { Instruction::GT, Instruction::LT },
226
14.5M
      { Instruction::SLT, Instruction::SGT },
227
14.5M
      { Instruction::SGT, Instruction::SLT }
228
14.5M
    };
229
230
14.5M
    if (
231
14.5M
      _swap == Instruction::SWAP1 &&
232
14.5M
      _op.type() == Operation &&
233
14.5M
      swappableOps.count(_op.instruction())
234
14.5M
    )
235
1.34k
    {
236
1.34k
      *_out = swappableOps.at(_op.instruction());
237
1.34k
      return true;
238
1.34k
    }
239
14.5M
    else
240
14.5M
      return false;
241
14.5M
  }
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
14.5M
  {
253
14.5M
    if (
254
14.5M
      SemanticInformation::isDupInstruction(_dupN) &&
255
14.5M
      SemanticInformation::isSwapInstruction(_swapN) &&
256
14.5M
      getDupNumber(_dupN.instruction()) == getSwapNumber(_swapN.instruction())
257
14.5M
    )
258
1.64k
    {
259
1.64k
      *_out = _dupN;
260
1.64k
      return true;
261
1.64k
    }
262
14.5M
    else
263
14.5M
      return false;
264
14.5M
  }
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
14.4M
  {
278
14.4M
    if (
279
14.4M
      _iszero1 == Instruction::ISZERO &&
280
14.4M
      _iszero2 == Instruction::ISZERO &&
281
14.4M
      _pushTag.type() == PushTag &&
282
14.4M
      _jumpi == Instruction::JUMPI
283
14.4M
    )
284
16
    {
285
16
      *_out = _pushTag;
286
16
      *_out = _jumpi;
287
16
      return true;
288
16
    }
289
14.4M
    else
290
14.4M
      return false;
291
14.4M
  }
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
14.4M
  {
304
14.4M
    if (
305
14.4M
      _eq == Instruction::EQ &&
306
14.4M
      _iszero == Instruction::ISZERO &&
307
14.4M
      _pushTag.type() == PushTag &&
308
14.4M
      _jumpi == Instruction::JUMPI
309
14.4M
    )
310
52
    {
311
52
      *_out = AssemblyItem(Instruction::SUB, _eq.location());
312
52
      *_out = _pushTag;
313
52
      *_out = _jumpi;
314
52
      return true;
315
52
    }
316
14.4M
    else
317
14.4M
      return false;
318
14.4M
  }
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
14.3M
  {
333
14.3M
    if (
334
14.3M
      _pushTag1.type() == PushTag &&
335
14.3M
      _jumpi == Instruction::JUMPI &&
336
14.3M
      _pushTag2.type() == PushTag &&
337
14.3M
      _jump == Instruction::JUMP &&
338
14.3M
      _tag1.type() == Tag &&
339
14.3M
      _pushTag1.data() == _tag1.data()
340
14.3M
    )
341
1.14k
    {
342
1.14k
      *_out = AssemblyItem(Instruction::ISZERO, _jumpi.location());
343
1.14k
      *_out = _pushTag2;
344
1.14k
      *_out = _jumpi;
345
1.14k
      *_out = _tag1;
346
1.14k
      return true;
347
1.14k
    }
348
14.3M
    else
349
14.3M
      return false;
350
14.3M
  }
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
14.5M
  {
362
14.5M
    if (
363
14.5M
      _pushTag.type() == PushTag &&
364
14.5M
      (_jump == Instruction::JUMP || _jump == Instruction::JUMPI) &&
365
14.5M
      _tag.type() == Tag &&
366
14.5M
      _pushTag.data() == _tag.data()
367
14.5M
    )
368
23.2k
    {
369
23.2k
      if (_jump == Instruction::JUMPI)
370
67
        *_out = AssemblyItem(Instruction::POP, _jump.location());
371
23.2k
      *_out = _tag;
372
23.2k
      return true;
373
23.2k
    }
374
14.4M
    else
375
14.4M
      return false;
376
14.5M
  }
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
14.4M
  {
388
14.4M
    if (_and != Instruction::AND)
389
14.3M
      return false;
390
63.1k
    if (
391
63.1k
      _pushTag.type() == PushTag &&
392
63.1k
      _pushConstant.type() == Push &&
393
63.1k
      (_pushConstant.data() & u256(0xFFFFFFFF)) == u256(0xFFFFFFFF)
394
63.1k
    )
395
0
    {
396
0
      *_out = _pushTag;
397
0
      return true;
398
0
    }
399
63.1k
    else if (
400
      // tag and constant are swapped
401
63.1k
      _pushConstant.type() == PushTag &&
402
63.1k
      _pushTag.type() == Push &&
403
63.1k
      (_pushTag.data() & u256(0xFFFFFFFF)) == u256(0xFFFFFFFF)
404
63.1k
    )
405
0
    {
406
0
      *_out = _pushConstant;
407
0
      return true;
408
0
    }
409
63.1k
    else
410
63.1k
      return false;
411
63.1k
  }
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
14.4M
  {
423
14.4M
    return (
424
14.4M
      _push.type() == Push && _push.data() == 0 &&
425
14.4M
      _not == Instruction::NOT &&
426
14.4M
      _and == Instruction::AND
427
14.4M
    );
428
14.4M
  }
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
14.6M
  {
436
14.6M
    auto it = _state.items.begin() + static_cast<ptrdiff_t>(_state.i);
437
14.6M
    auto end = _state.items.end();
438
14.6M
    if (it == end)
439
0
      return false;
440
14.6M
    if (
441
14.6M
      it[0] != Instruction::JUMP &&
442
14.6M
      it[0] != Instruction::RETURN &&
443
14.6M
      it[0] != Instruction::STOP &&
444
14.6M
      it[0] != Instruction::INVALID &&
445
14.6M
      it[0] != Instruction::SELFDESTRUCT &&
446
14.6M
      it[0] != Instruction::REVERT
447
14.6M
    )
448
13.5M
      return false;
449
450
1.11M
    ptrdiff_t i = 1;
451
1.24M
    while (it + i != end && it[i].type() != Tag)
452
131k
      i++;
453
1.11M
    if (i > 1)
454
26.8k
    {
455
26.8k
      *_state.out = it[0];
456
26.8k
      _state.i += static_cast<size_t>(i);
457
26.8k
      return true;
458
26.8k
    }
459
1.08M
    else
460
1.08M
      return false;
461
1.11M
  }
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
249M
{
472
249M
  if (!Method::apply(_state))
473
234M
    applyMethods(_state, _other...);
474
249M
}
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
14.7M
{
472
14.7M
  if (!Method::apply(_state))
473
14.7M
    applyMethods(_state, _other...);
474
14.7M
}
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
14.7M
{
472
14.7M
  if (!Method::apply(_state))
473
14.7M
    applyMethods(_state, _other...);
474
14.7M
}
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
14.7M
{
472
14.7M
  if (!Method::apply(_state))
473
14.6M
    applyMethods(_state, _other...);
474
14.7M
}
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
14.6M
{
472
14.6M
  if (!Method::apply(_state))
473
14.6M
    applyMethods(_state, _other...);
474
14.6M
}
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
14.6M
{
472
14.6M
  if (!Method::apply(_state))
473
14.6M
    applyMethods(_state, _other...);
474
14.6M
}
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
14.6M
{
472
14.6M
  if (!Method::apply(_state))
473
14.6M
    applyMethods(_state, _other...);
474
14.6M
}
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
14.6M
{
472
14.6M
  if (!Method::apply(_state))
473
14.6M
    applyMethods(_state, _other...);
474
14.6M
}
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
14.6M
{
472
14.6M
  if (!Method::apply(_state))
473
14.6M
    applyMethods(_state, _other...);
474
14.6M
}
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
14.6M
{
472
14.6M
  if (!Method::apply(_state))
473
14.6M
    applyMethods(_state, _other...);
474
14.6M
}
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
14.6M
{
472
14.6M
  if (!Method::apply(_state))
473
14.6M
    applyMethods(_state, _other...);
474
14.6M
}
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
14.6M
{
472
14.6M
  if (!Method::apply(_state))
473
14.6M
    applyMethods(_state, _other...);
474
14.6M
}
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
14.6M
{
472
14.6M
  if (!Method::apply(_state))
473
14.6M
    applyMethods(_state, _other...);
474
14.6M
}
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
14.6M
{
472
14.6M
  if (!Method::apply(_state))
473
14.6M
    applyMethods(_state, _other...);
474
14.6M
}
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
14.6M
{
472
14.6M
  if (!Method::apply(_state))
473
14.6M
    applyMethods(_state, _other...);
474
14.6M
}
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
14.6M
{
472
14.6M
  if (!Method::apply(_state))
473
14.6M
    applyMethods(_state, _other...);
474
14.6M
}
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
14.6M
{
472
14.6M
  if (!Method::apply(_state))
473
14.6M
    applyMethods(_state, _other...);
474
14.6M
}
PeepholeOptimiser.cpp:void (anonymous namespace)::applyMethods<(anonymous namespace)::Identity>((anonymous namespace)::OptimiserState&, (anonymous namespace)::Identity)
Line
Count
Source
471
14.6M
{
472
14.6M
  if (!Method::apply(_state))
473
0
    applyMethods(_state, _other...);
474
14.6M
}
475
476
size_t numberOfPops(AssemblyItems const& _items)
477
144k
{
478
144k
  return static_cast<size_t>(std::count(_items.begin(), _items.end(), Instruction::POP));
479
144k
}
480
481
}
482
483
bool PeepholeOptimiser::optimise()
484
114k
{
485
  // Avoid referencing immutables too early by using approx. counting in bytesRequired()
486
114k
  auto const approx = evmasm::Precision::Approximate;
487
114k
  OptimiserState state {m_items, 0, std::back_inserter(m_optimisedItems)};
488
14.8M
  while (state.i < m_items.size())
489
14.7M
    applyMethods(
490
14.7M
      state,
491
14.7M
      PushPop(), OpPop(), OpStop(), OpReturnRevert(), DoublePush(), DoubleSwap(), CommutativeSwap(), SwapComparison(),
492
14.7M
      DupSwap(), IsZeroIsZeroJumpI(), EqIsZeroJumpI(), DoubleJump(), JumpToNext(), UnreachableCode(),
493
14.7M
      TagConjunctions(), TruthyAnd(), Identity()
494
14.7M
    );
495
114k
  if (m_optimisedItems.size() < m_items.size() || (
496
72.7k
    m_optimisedItems.size() == m_items.size() && (
497
72.3k
      evmasm::bytesRequired(m_optimisedItems, 3, approx) < evmasm::bytesRequired(m_items, 3, approx) ||
498
72.3k
      numberOfPops(m_optimisedItems) > numberOfPops(m_items)
499
72.3k
    )
500
72.7k
  ))
501
42.8k
  {
502
42.8k
    m_items = std::move(m_optimisedItems);
503
42.8k
    return true;
504
42.8k
  }
505
71.1k
  else
506
71.1k
    return false;
507
114k
}