Coverage Report

Created: 2025-06-24 07:59

/src/solidity/libyul/optimiser/ConditionalUnsimplifier.cpp
Line
Count
Source
1
/*
2
  This file is part of solidity.
3
4
  solidity is free software: you can redistribute it and/or modify
5
  it under the terms of the GNU General Public License as published by
6
  the Free Software Foundation, either version 3 of the License, or
7
  (at your option) any later version.
8
9
  solidity is distributed in the hope that it will be useful,
10
  but WITHOUT ANY WARRANTY; without even the implied warranty of
11
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
  GNU General Public License for more details.
13
14
  You should have received a copy of the GNU General Public License
15
  along with solidity.  If not, see <http://www.gnu.org/licenses/>.
16
*/
17
// SPDX-License-Identifier: GPL-3.0
18
#include <libyul/optimiser/ConditionalUnsimplifier.h>
19
#include <libyul/optimiser/Semantics.h>
20
#include <libyul/AST.h>
21
#include <libyul/Utilities.h>
22
#include <libyul/optimiser/NameCollector.h>
23
#include <libyul/ControlFlowSideEffectsCollector.h>
24
#include <libsolutil/CommonData.h>
25
26
using namespace solidity;
27
using namespace solidity::yul;
28
using namespace solidity::util;
29
30
void ConditionalUnsimplifier::run(OptimiserStepContext& _context, Block& _ast)
31
369k
{
32
369k
  ConditionalUnsimplifier{
33
369k
    _context.dialect,
34
369k
    ControlFlowSideEffectsCollector{_context.dialect, _ast}.functionSideEffectsNamed()
35
369k
  }(_ast);
36
369k
}
37
38
void ConditionalUnsimplifier::operator()(Switch& _switch)
39
241k
{
40
241k
  visit(*_switch.expression);
41
241k
  if (!std::holds_alternative<Identifier>(*_switch.expression))
42
18.3k
  {
43
18.3k
    ASTModifier::operator()(_switch);
44
18.3k
    return;
45
18.3k
  }
46
222k
  YulName expr = std::get<Identifier>(*_switch.expression).name;
47
222k
  for (auto& _case: _switch.cases)
48
660k
  {
49
660k
    if (_case.value)
50
497k
    {
51
497k
      (*this)(*_case.value);
52
497k
      if (
53
497k
        !_case.body.statements.empty() &&
54
497k
        std::holds_alternative<Assignment>(_case.body.statements.front())
55
497k
      )
56
488k
      {
57
488k
        Assignment const& assignment = std::get<Assignment>(_case.body.statements.front());
58
488k
        if (
59
488k
          assignment.variableNames.size() == 1 &&
60
488k
          assignment.variableNames.front().name == expr &&
61
488k
          std::holds_alternative<Literal>(*assignment.value) &&
62
488k
          std::get<Literal>(*assignment.value).value == _case.value->value
63
488k
        )
64
484k
          _case.body.statements.erase(_case.body.statements.begin());
65
488k
      }
66
497k
    }
67
660k
    (*this)(_case.body);
68
660k
  }
69
222k
}
70
71
void ConditionalUnsimplifier::operator()(Block& _block)
72
6.10M
{
73
6.10M
  walkVector(_block.statements);
74
6.10M
  iterateReplacingWindow<2>(
75
6.10M
    _block.statements,
76
6.10M
    [&](Statement& _stmt1, Statement& _stmt2) -> std::optional<std::vector<Statement>>
77
43.5M
    {
78
43.5M
      if (std::holds_alternative<If>(_stmt1))
79
723k
      {
80
723k
        If& _if = std::get<If>(_stmt1);
81
723k
        if (
82
723k
          std::holds_alternative<Identifier>(*_if.condition) &&
83
723k
          !_if.body.statements.empty()
84
723k
        )
85
648k
        {
86
648k
          YulName condition = std::get<Identifier>(*_if.condition).name;
87
648k
          if (
88
648k
            std::holds_alternative<Assignment>(_stmt2) &&
89
648k
            TerminationFinder(m_dialect, &m_functionSideEffects).controlFlowKind(_if.body.statements.back()) !=
90
538k
              TerminationFinder::ControlFlow::FlowOut
91
648k
          )
92
538k
          {
93
538k
            Assignment const& assignment = std::get<Assignment>(_stmt2);
94
538k
            if (
95
538k
              assignment.variableNames.size() == 1 &&
96
538k
              assignment.variableNames.front().name == condition &&
97
538k
              std::holds_alternative<Literal>(*assignment.value) &&
98
538k
              std::get<Literal>(*assignment.value).value.value() == 0
99
538k
            )
100
538k
              return {make_vector<Statement>(std::move(_stmt1))};
101
538k
          }
102
648k
        }
103
723k
      }
104
42.9M
      return {};
105
43.5M
    }
106
6.10M
  );
107
6.10M
}