Coverage Report

Created: 2022-08-24 06:39

/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
}