Coverage Report

Created: 2025-09-04 07:34

/src/solidity/libyul/optimiser/StructuralSimplifier.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/StructuralSimplifier.h>
19
#include <libyul/AST.h>
20
#include <libyul/Utilities.h>
21
#include <libsolutil/CommonData.h>
22
#include <libsolutil/Visitor.h>
23
24
using namespace solidity;
25
using namespace solidity::yul;
26
27
using OptionalStatements = std::optional<std::vector<Statement>>;
28
29
namespace
30
{
31
32
OptionalStatements replaceConstArgSwitch(Switch& _switchStmt, u256 const& _constExprVal)
33
15.5k
{
34
15.5k
  Block* matchingCaseBlock = nullptr;
35
15.5k
  Case* defaultCase = nullptr;
36
37
15.5k
  for (auto& _case: _switchStmt.cases)
38
37.5k
  {
39
37.5k
    if (_case.value && _case.value->value.value() == _constExprVal)
40
3.06k
    {
41
3.06k
      matchingCaseBlock = &_case.body;
42
3.06k
      break;
43
3.06k
    }
44
34.4k
    else if (!_case.value)
45
9.75k
      defaultCase = &_case;
46
37.5k
  }
47
48
15.5k
  if (!matchingCaseBlock && defaultCase)
49
9.75k
    matchingCaseBlock = &defaultCase->body;
50
51
15.5k
  if (matchingCaseBlock)
52
12.8k
    return util::make_vector<Statement>(std::move(*matchingCaseBlock));
53
2.70k
  else
54
2.70k
    return std::optional<std::vector<Statement>>{std::vector<Statement>{}};
55
15.5k
}
56
57
std::optional<u256> hasLiteralValue(Expression const& _expression)
58
3.39M
{
59
3.39M
  if (std::holds_alternative<Literal>(_expression))
60
720k
    return std::get<Literal>(_expression).value.value();
61
2.67M
  else
62
2.67M
    return std::nullopt;
63
3.39M
}
64
65
bool expressionAlwaysTrue(Expression const& _expression)
66
994k
{
67
994k
  if (std::optional<u256> value = hasLiteralValue(_expression))
68
58.8k
    return *value != 0;
69
936k
  else
70
936k
    return false;
71
994k
}
72
73
bool expressionAlwaysFalse(Expression const& _expression)
74
2.10M
{
75
2.10M
  if (std::optional<u256> value = hasLiteralValue(_expression))
76
645k
    return *value == 0;
77
1.46M
  else
78
1.46M
    return false;
79
2.10M
}
80
81
}
82
83
void StructuralSimplifier::run(OptimiserStepContext&, Block& _ast)
84
359k
{
85
359k
  StructuralSimplifier{}(_ast);
86
359k
}
87
88
void StructuralSimplifier::operator()(Block& _block)
89
7.22M
{
90
7.22M
  simplify(_block.statements);
91
7.22M
}
92
93
void StructuralSimplifier::simplify(std::vector<yul::Statement>& _statements)
94
7.30M
{
95
7.30M
  util::GenericVisitor visitor{
96
7.30M
    util::VisitorFallback<OptionalStatements>{},
97
7.30M
    [&](If& _ifStmt) -> OptionalStatements {
98
994k
      if (expressionAlwaysTrue(*_ifStmt.condition))
99
21.6k
        return {std::move(_ifStmt.body.statements)};
100
973k
      else if (expressionAlwaysFalse(*_ifStmt.condition))
101
37.1k
        return {std::vector<Statement>{}};
102
936k
      return {};
103
994k
    },
104
7.30M
    [&](Switch& _switchStmt) -> OptionalStatements {
105
290k
      if (std::optional<u256> const constExprVal = hasLiteralValue(*_switchStmt.expression))
106
15.5k
        return replaceConstArgSwitch(_switchStmt, constExprVal.value());
107
275k
      return {};
108
290k
    },
109
7.30M
    [&](ForLoop& _forLoop) -> OptionalStatements {
110
1.13M
      if (expressionAlwaysFalse(*_forLoop.condition))
111
3.58k
        return {std::move(_forLoop.pre.statements)};
112
1.13M
      return {};
113
1.13M
    }
114
7.30M
  };
115
116
7.30M
  util::iterateReplacing(
117
7.30M
    _statements,
118
7.30M
    [&](Statement& _stmt) -> OptionalStatements
119
58.1M
    {
120
58.1M
      OptionalStatements result = std::visit(visitor, _stmt);
121
58.1M
      if (result)
122
77.9k
        simplify(*result);
123
58.1M
      else
124
58.1M
        visit(_stmt);
125
58.1M
      return result;
126
58.1M
    }
127
7.30M
  );
128
7.30M
}