Coverage Report

Created: 2025-09-08 08:10

/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
16.0k
{
34
16.0k
  Block* matchingCaseBlock = nullptr;
35
16.0k
  Case* defaultCase = nullptr;
36
37
16.0k
  for (auto& _case: _switchStmt.cases)
38
38.6k
  {
39
38.6k
    if (_case.value && _case.value->value.value() == _constExprVal)
40
3.18k
    {
41
3.18k
      matchingCaseBlock = &_case.body;
42
3.18k
      break;
43
3.18k
    }
44
35.5k
    else if (!_case.value)
45
10.0k
      defaultCase = &_case;
46
38.6k
  }
47
48
16.0k
  if (!matchingCaseBlock && defaultCase)
49
10.0k
    matchingCaseBlock = &defaultCase->body;
50
51
16.0k
  if (matchingCaseBlock)
52
13.2k
    return util::make_vector<Statement>(std::move(*matchingCaseBlock));
53
2.80k
  else
54
2.80k
    return std::optional<std::vector<Statement>>{std::vector<Statement>{}};
55
16.0k
}
56
57
std::optional<u256> hasLiteralValue(Expression const& _expression)
58
3.54M
{
59
3.54M
  if (std::holds_alternative<Literal>(_expression))
60
763k
    return std::get<Literal>(_expression).value.value();
61
2.78M
  else
62
2.78M
    return std::nullopt;
63
3.54M
}
64
65
bool expressionAlwaysTrue(Expression const& _expression)
66
1.02M
{
67
1.02M
  if (std::optional<u256> value = hasLiteralValue(_expression))
68
61.0k
    return *value != 0;
69
967k
  else
70
967k
    return false;
71
1.02M
}
72
73
bool expressionAlwaysFalse(Expression const& _expression)
74
2.21M
{
75
2.21M
  if (std::optional<u256> value = hasLiteralValue(_expression))
76
686k
    return *value == 0;
77
1.52M
  else
78
1.52M
    return false;
79
2.21M
}
80
81
}
82
83
void StructuralSimplifier::run(OptimiserStepContext&, Block& _ast)
84
374k
{
85
374k
  StructuralSimplifier{}(_ast);
86
374k
}
87
88
void StructuralSimplifier::operator()(Block& _block)
89
7.60M
{
90
7.60M
  simplify(_block.statements);
91
7.60M
}
92
93
void StructuralSimplifier::simplify(std::vector<yul::Statement>& _statements)
94
7.69M
{
95
7.69M
  util::GenericVisitor visitor{
96
7.69M
    util::VisitorFallback<OptionalStatements>{},
97
7.69M
    [&](If& _ifStmt) -> OptionalStatements {
98
1.02M
      if (expressionAlwaysTrue(*_ifStmt.condition))
99
22.6k
        return {std::move(_ifStmt.body.statements)};
100
1.00M
      else if (expressionAlwaysFalse(*_ifStmt.condition))
101
38.3k
        return {std::vector<Statement>{}};
102
967k
      return {};
103
1.02M
    },
104
7.69M
    [&](Switch& _switchStmt) -> OptionalStatements {
105
303k
      if (std::optional<u256> const constExprVal = hasLiteralValue(*_switchStmt.expression))
106
16.0k
        return replaceConstArgSwitch(_switchStmt, constExprVal.value());
107
287k
      return {};
108
303k
    },
109
7.69M
    [&](ForLoop& _forLoop) -> OptionalStatements {
110
1.20M
      if (expressionAlwaysFalse(*_forLoop.condition))
111
3.88k
        return {std::move(_forLoop.pre.statements)};
112
1.20M
      return {};
113
1.20M
    }
114
7.69M
  };
115
116
7.69M
  util::iterateReplacing(
117
7.69M
    _statements,
118
7.69M
    [&](Statement& _stmt) -> OptionalStatements
119
60.8M
    {
120
60.8M
      OptionalStatements result = std::visit(visitor, _stmt);
121
60.8M
      if (result)
122
80.9k
        simplify(*result);
123
60.7M
      else
124
60.7M
        visit(_stmt);
125
60.8M
      return result;
126
60.8M
    }
127
7.69M
  );
128
7.69M
}