Coverage Report

Created: 2025-06-24 07:59

/src/solidity/libyul/backends/evm/EVMMetrics.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
* Module providing metrics for the EVM optimizer.
20
*/
21
22
#include <libyul/backends/evm/EVMMetrics.h>
23
24
#include <libyul/AST.h>
25
#include <libyul/Exceptions.h>
26
#include <libyul/Utilities.h>
27
#include <libyul/backends/evm/EVMDialect.h>
28
29
#include <libevmasm/Instruction.h>
30
#include <libevmasm/GasMeter.h>
31
32
#include <libsolutil/CommonData.h>
33
34
using namespace solidity;
35
using namespace solidity::yul;
36
using namespace solidity::util;
37
38
bigint GasMeter::costs(Expression const& _expression) const
39
1.50M
{
40
1.50M
  return combineCosts(GasMeterVisitor::costs(_expression, m_dialect, m_isCreation));
41
1.50M
}
42
43
bigint GasMeter::instructionCosts(evmasm::Instruction _instruction) const
44
1.43M
{
45
1.43M
  return combineCosts(GasMeterVisitor::instructionCosts(_instruction, m_dialect, m_isCreation));
46
1.43M
}
47
48
bigint GasMeter::combineCosts(std::pair<bigint, bigint> _costs) const
49
2.94M
{
50
2.94M
  return _costs.first * m_runs + _costs.second;
51
2.94M
}
52
53
54
std::pair<bigint, bigint> GasMeterVisitor::costs(
55
  Expression const& _expression,
56
  EVMDialect const& _dialect,
57
  bool _isCreation
58
)
59
1.50M
{
60
1.50M
  GasMeterVisitor gmv(_dialect, _isCreation);
61
1.50M
  gmv.visit(_expression);
62
1.50M
  return {gmv.m_runGas, gmv.m_dataGas};
63
1.50M
}
64
65
std::pair<bigint, bigint> GasMeterVisitor::instructionCosts(
66
  evmasm::Instruction _instruction,
67
  EVMDialect const& _dialect,
68
  bool _isCreation
69
)
70
1.43M
{
71
1.43M
  GasMeterVisitor gmv(_dialect, _isCreation);
72
1.43M
  gmv.instructionCostsInternal(_instruction);
73
1.43M
  return {gmv.m_runGas, gmv.m_dataGas};
74
1.43M
}
75
76
void GasMeterVisitor::operator()(FunctionCall const& _funCall)
77
37.9k
{
78
37.9k
  ASTWalker::operator()(_funCall);
79
37.9k
  if (BuiltinFunctionForEVM const* builtin = resolveBuiltinFunctionForEVM(_funCall.functionName, m_dialect))
80
37.9k
    if (builtin->instruction)
81
37.9k
    {
82
37.9k
      instructionCostsInternal(*builtin->instruction);
83
37.9k
      return;
84
37.9k
    }
85
0
  yulAssert(false, "Functions not implemented.");
86
0
}
87
88
void GasMeterVisitor::operator()(Literal const& _lit)
89
1.46M
{
90
1.46M
  m_runGas += evmasm::GasMeter::pushGas(_lit.value.value(), m_dialect.evmVersion());
91
92
1.46M
  m_dataGas += singleByteDataGas();
93
1.46M
  if (!m_dialect.evmVersion().hasPush0() || _lit.value.value() != u256(0))
94
1.46M
    m_dataGas += evmasm::GasMeter::dataGas(
95
1.46M
      toCompactBigEndian(_lit.value.value(), 1),
96
1.46M
      m_isCreation,
97
1.46M
      m_dialect.evmVersion()
98
1.46M
    );
99
1.46M
}
100
101
void GasMeterVisitor::operator()(Identifier const&)
102
75.8k
{
103
75.8k
  m_runGas += evmasm::GasMeter::runGas(evmasm::Instruction::DUP1, m_dialect.evmVersion());
104
75.8k
  m_dataGas += singleByteDataGas();
105
75.8k
}
106
107
bigint GasMeterVisitor::singleByteDataGas() const
108
3.01M
{
109
3.01M
  if (m_isCreation)
110
1.78M
    return evmasm::GasCosts::txDataNonZeroGas(m_dialect.evmVersion());
111
1.23M
  else
112
1.23M
    return evmasm::GasCosts::createDataGas;
113
3.01M
}
114
115
void GasMeterVisitor::instructionCostsInternal(evmasm::Instruction _instruction)
116
1.47M
{
117
1.47M
  if (_instruction == evmasm::Instruction::EXP)
118
34.2k
    m_runGas += evmasm::GasCosts::expGas + evmasm::GasCosts::expByteGas(m_dialect.evmVersion());
119
1.43M
  else if (_instruction == evmasm::Instruction::KECCAK256)
120
    // Assumes that Keccak-256 is computed on a single word (rounded up).
121
37.9k
    m_runGas += evmasm::GasCosts::keccak256Gas + evmasm::GasCosts::keccak256WordGas;
122
1.40M
  else
123
1.40M
    m_runGas += evmasm::GasMeter::runGas(_instruction, m_dialect.evmVersion());
124
1.47M
  m_dataGas += singleByteDataGas();
125
1.47M
}