Coverage Report

Created: 2022-08-24 06:31

/src/solidity/libevmasm/SimplificationRules.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 ExpressionClasses.cpp
20
 * @author Christian <c@ethdev.com>
21
 * @date 2015
22
 * Container for equivalence classes of expressions for use in common subexpression elimination.
23
 */
24
25
#include <libevmasm/SimplificationRules.h>
26
27
#include <libevmasm/ExpressionClasses.h>
28
#include <libevmasm/Assembly.h>
29
#include <libevmasm/RuleList.h>
30
#include <libsolutil/Assertions.h>
31
32
#include <utility>
33
#include <functional>
34
35
using namespace std;
36
using namespace solidity;
37
using namespace solidity::evmasm;
38
using namespace solidity::langutil;
39
40
SimplificationRule<Pattern> const* Rules::findFirstMatch(
41
  Expression const& _expr,
42
  ExpressionClasses const& _classes
43
)
44
0
{
45
0
  resetMatchGroups();
46
47
0
  assertThrow(_expr.item, OptimizerException, "");
48
0
  for (auto const& rule: m_rules[uint8_t(_expr.item->instruction())])
49
0
  {
50
0
    if (rule.pattern.matches(_expr, _classes))
51
0
      if (!rule.feasible || rule.feasible())
52
0
        return &rule;
53
54
0
    resetMatchGroups();
55
0
  }
56
0
  return nullptr;
57
0
}
58
59
bool Rules::isInitialized() const
60
0
{
61
0
  return !m_rules[uint8_t(Instruction::ADD)].empty();
62
0
}
63
64
void Rules::addRules(std::vector<SimplificationRule<Pattern>> const& _rules)
65
0
{
66
0
  for (auto const& r: _rules)
67
0
    addRule(r);
68
0
}
69
70
void Rules::addRule(SimplificationRule<Pattern> const& _rule)
71
0
{
72
0
  m_rules[uint8_t(_rule.pattern.instruction())].push_back(_rule);
73
0
}
74
75
Rules::Rules()
76
0
{
77
  // Multiple occurrences of one of these inside one rule must match the same equivalence class.
78
  // Constants.
79
0
  Pattern A(Push);
80
0
  Pattern B(Push);
81
0
  Pattern C(Push);
82
  // Anything.
83
0
  Pattern W;
84
0
  Pattern X;
85
0
  Pattern Y;
86
0
  Pattern Z;
87
0
  A.setMatchGroup(1, m_matchGroups);
88
0
  B.setMatchGroup(2, m_matchGroups);
89
0
  C.setMatchGroup(3, m_matchGroups);
90
0
  W.setMatchGroup(4, m_matchGroups);
91
0
  X.setMatchGroup(5, m_matchGroups);
92
0
  Y.setMatchGroup(6, m_matchGroups);
93
0
  Z.setMatchGroup(7, m_matchGroups);
94
95
0
  addRules(simplificationRuleList(nullopt, A, B, C, W, X, Y, Z));
96
0
  assertThrow(isInitialized(), OptimizerException, "Rule list not properly initialized.");
97
0
}
98
99
Pattern::Pattern(Instruction _instruction, std::initializer_list<Pattern> _arguments):
100
  m_type(Operation),
101
  m_instruction(_instruction),
102
  m_arguments(_arguments)
103
0
{
104
0
}
105
106
void Pattern::setMatchGroup(unsigned _group, map<unsigned, Expression const*>& _matchGroups)
107
0
{
108
0
  m_matchGroup = _group;
109
0
  m_matchGroups = &_matchGroups;
110
0
}
111
112
bool Pattern::matches(Expression const& _expr, ExpressionClasses const& _classes) const
113
0
{
114
0
  if (!matchesBaseItem(_expr.item))
115
0
    return false;
116
0
  if (m_matchGroup)
117
0
  {
118
0
    if (!m_matchGroups->count(m_matchGroup))
119
0
      (*m_matchGroups)[m_matchGroup] = &_expr;
120
0
    else if ((*m_matchGroups)[m_matchGroup]->id != _expr.id)
121
0
      return false;
122
0
  }
123
0
  assertThrow(m_arguments.size() == 0 || _expr.arguments.size() == m_arguments.size(), OptimizerException, "");
124
0
  for (size_t i = 0; i < m_arguments.size(); ++i)
125
0
    if (!m_arguments[i].matches(_classes.representative(_expr.arguments[i]), _classes))
126
0
      return false;
127
0
  return true;
128
0
}
129
130
AssemblyItem Pattern::toAssemblyItem(SourceLocation const& _location) const
131
0
{
132
0
  if (m_type == Operation)
133
0
    return AssemblyItem(m_instruction, _location);
134
0
  else
135
0
    return AssemblyItem(m_type, data(), _location);
136
0
}
137
138
string Pattern::toString() const
139
0
{
140
0
  stringstream s;
141
0
  switch (m_type)
142
0
  {
143
0
  case Operation:
144
0
    s << instructionInfo(m_instruction).name;
145
0
    break;
146
0
  case Push:
147
0
    if (m_data)
148
0
      s << "PUSH " << hex << data();
149
0
    else
150
0
      s << "PUSH ";
151
0
    break;
152
0
  case UndefinedItem:
153
0
    s << "ANY";
154
0
    break;
155
0
  default:
156
0
    if (m_data)
157
0
      s << "t=" << dec << m_type << " d=" << hex << data();
158
0
    else
159
0
      s << "t=" << dec << m_type << " d: nullptr";
160
0
    break;
161
0
  }
162
0
  if (!m_requireDataMatch)
163
0
    s << " ~";
164
0
  if (m_matchGroup)
165
0
    s << "[" << dec << m_matchGroup << "]";
166
0
  s << "(";
167
0
  for (Pattern const& p: m_arguments)
168
0
    s << p.toString() << ", ";
169
0
  s << ")";
170
0
  return s.str();
171
0
}
172
173
bool Pattern::matchesBaseItem(AssemblyItem const* _item) const
174
0
{
175
0
  if (m_type == UndefinedItem)
176
0
    return true;
177
0
  if (!_item)
178
0
    return false;
179
0
  if (m_type != _item->type())
180
0
    return false;
181
0
  else if (m_type == Operation)
182
0
    return m_instruction == _item->instruction();
183
0
  else if (m_requireDataMatch)
184
0
    return data() == _item->data();
185
0
  return true;
186
0
}
187
188
Pattern::Expression const& Pattern::matchGroupValue() const
189
0
{
190
0
  assertThrow(m_matchGroup > 0, OptimizerException, "");
191
0
  assertThrow(!!m_matchGroups, OptimizerException, "");
192
0
  assertThrow((*m_matchGroups)[m_matchGroup], OptimizerException, "");
193
0
  return *(*m_matchGroups)[m_matchGroup];
194
0
}
195
196
u256 const& Pattern::data() const
197
0
{
198
0
  assertThrow(m_data, OptimizerException, "");
199
0
  return *m_data;
200
0
}
201
202
ExpressionTemplate::ExpressionTemplate(Pattern const& _pattern, SourceLocation const& _location)
203
0
{
204
0
  if (_pattern.matchGroup())
205
0
  {
206
0
    hasId = true;
207
0
    id = _pattern.id();
208
0
  }
209
0
  else
210
0
  {
211
0
    hasId = false;
212
0
    item = _pattern.toAssemblyItem(_location);
213
0
  }
214
0
  for (auto const& arg: _pattern.arguments())
215
0
    arguments.emplace_back(arg, _location);
216
0
}
217
218
string ExpressionTemplate::toString() const
219
0
{
220
0
  stringstream s;
221
0
  if (hasId)
222
0
    s << id;
223
0
  else
224
0
    s << item;
225
0
  s << "(";
226
0
  for (auto const& arg: arguments)
227
0
    s << arg.toString();
228
0
  s << ")";
229
0
  return s.str();
230
0
}