/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 | } |