Skip to content

evm: Push 64-bit values to the stack without a temporary - #1799

Merged
chfast merged 1 commit into
masterfrom
evm/push-uint64
Nov 1, 2026
Merged

chfast merged 1 commit into
masterfrom
evm/push-uint64

Conversation

@chfast

@chfast chfast commented Nov 1, 2026 •

Copy link
Copy Markdown
Member

GCC 15 and 16 compile stack.push() of an integer by building the uint256 temporary in a stack slot and copying it to the EVM stack: 3 stores, 2 loads and 2 more stores instead of the 4 stores GCC 14 and Clang emit. This slows down PC, GAS, CALLDATASIZE, RETURNDATASIZE, MSIZE and the other instructions pushing an integer: CodSpeed measures them up to 20% slower with GCC 15 than with GCC 14.

Add a push() overload for uint64_t which assigns the value to the stack slot, so GCC 15 and 16 compile these instructions as GCC 14 does. The two pushes of int64_t values, GAS and PC in Advanced, now cast explicitly instead of relying on the conversion to uint256.

@codspeed

codspeed Bot commented Nov 1, 2026 •

Copy link
Copy Markdown
Contributor

Merging this PR will regress 47 benchmarks

2 warnings

⚠️ 711 benchmarks with a significant change ran on different hardware

Their base and head results were measured on machines with a different CPU, core count or memory, so the changes might not come from the code. Run base and head on the same runner type.

Learn more about Macro Runners

See affected benchmarks

⚠️ 711 benchmarks with a significant change ran in a different software environment

Their base and head results were measured with a different OS or toolchain, such as compiler, runtime or library versions, so the changes might come from this difference rather than from the code. Open an affected benchmark to see what changed.

See affected benchmarks

⚡ 664 improved benchmarks
❌ 47 regressed benchmarks
✅ 188 untouched benchmarks

Warning

Please fix the performance issues or acknowledge them on CodSpeed.

Performance Changes

Benchmark BASE HEAD Efficiency
❌ test_ripemd160_fixed_size[fork_Osaka-blockchain_test-size_1024-benchmark-gas-value_1M] 12 ms 43.3 ms -72.2%
❌ test_ripemd160[fork_Osaka-blockchain_test-benchmark-gas-value_1M] 12 ms 42.5 ms -71.72%
❌ test_ripemd160_fixed_size[fork_Osaka-blockchain_test-size_256-benchmark-gas-value_1M] 10.7 ms 35.8 ms -70.16%
❌ test_ripemd160_fixed_size[fork_Osaka-blockchain_test-size_0-benchmark-gas-value_1M] 7.6 ms 19.4 ms -60.56%
❌ test_ripemd160_fixed_size[fork_Osaka-blockchain_test-size_32-benchmark-gas-value_1M] 6.9 ms 17 ms -59.1%
❌ modexp<expmod_execute_evmone>[mod_len:32/mod_tz:254/exp_bits:256] 114.1 µs 136.3 µs -16.28%
❌ modexp<expmod_execute_evmone>[mod_len:32/mod_tz:254/exp_bits:33] 29 µs 32.1 µs -9.53%
❌ precompile<ecrecover, ecrecover_execute_libsecp256k1> 3 ms 3.3 ms -9.31%
❌ precompile<p256verify, p256verify_execute> 12.2 ms 13.4 ms -9.17%
❌ test_p256verify[fork_Osaka-blockchain_test-p256verify_modular_comp_x_coordinate_exceeds_n-benchmark-gas-value_1M] 179.7 ms 197.5 ms -9.02%
❌ test_p256verify[fork_Osaka-blockchain_test-p256verify-benchmark-gas-value_1M] 172.6 ms 189.6 ms -8.98%
❌ test_ecrecover[fork_Osaka-blockchain_test-ecrecover-benchmark-gas-value_1M] 90.2 ms 98.9 ms -8.76%
❌ precompile<ecrecover, ecrecover_execute_evmone> 11.1 ms 12.1 ms -8.58%
❌ test_auth_transaction[fork_Osaka-blockchain_test-zero_delegation_True-empty_authority_True-benchmark-gas-value_1M] 47 ms 50.6 ms -7.04%
❌ test_auth_transaction[fork_Osaka-blockchain_test-zero_delegation_True-empty_authority_False-benchmark-gas-value_1M] 47.3 ms 50.8 ms -6.92%
❌ test_auth_transaction[fork_Osaka-blockchain_test-zero_delegation_False-empty_authority_False-benchmark-gas-value_1M] 47.7 ms 51.2 ms -6.84%
❌ test_auth_transaction[fork_Osaka-blockchain_test-zero_delegation_False-empty_authority_True-benchmark-gas-value_1M] 47.7 ms 51.2 ms -6.78%
❌ test_arithmetic[fork_Osaka-blockchain_test-opcode_MUL--benchmark-gas-value_1M] 12.4 ms 13.1 ms -5.61%
❌ test_calldatacopy_from_origin[fork_Osaka-blockchain_test-calldata_size_32-fixed_src_dst_True-mem_size_1024-benchmark-gas-value_1M] 11.5 ms 11.9 ms -3.16%
❌ test_calldatacopy_from_origin[fork_Osaka-blockchain_test-calldata_size_32-fixed_src_dst_True-mem_size_32-benchmark-gas-value_1M] 11.5 ms 11.9 ms -3.13%
... ... ... ... ...

ℹ️ Only the first 20 benchmarks are displayed. Go to the app to view all benchmarks.

Tip

Investigate this regression by commenting @codspeedbot fix this regression on this PR, or directly use the CodSpeed MCP with your agent.


Comparing evm/push-uint64 (7693d83) with master (1775e4d)

Open in CodSpeed

@codecov

codecov Bot commented Nov 1, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 98.24%. Comparing base (1775e4d) to head (7693d83).
⚠️ Report is 1 commits behind head on master.

Additional details and impacted files
@@           Coverage Diff           @@
##           master    #1799   +/-   ##
=======================================
  Coverage   98.24%   98.24%           
=======================================
  Files         186      186           
  Lines       17175    17176    +1     
  Branches     3921     3921           
=======================================
+ Hits        16873    16874    +1     
  Misses        233      233           
  Partials       69       69           
Flag Coverage Δ
eest-develop-gmp 26.96% <66.66%> (+<0.01%) ⬆️
eest-legacy 17.22% <66.66%> (+<0.01%) ⬆️
eest-libsecp256k1 29.11% <66.66%> (+<0.01%) ⬆️
eest-stable 84.24% <100.00%> (+<0.01%) ⬆️
evmone-unittests 94.11% <100.00%> (+<0.01%) ⬆️
riscv64 94.82% <100.00%> (+<0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Components Coverage Δ
core 96.62% <100.00%> (+<0.01%) ⬆️
tooling 94.87% <ø> (ø)
tests 99.82% <ø> (ø)
Files with missing lines Coverage Δ
lib/evmone/advanced_instructions.cpp 96.87% <100.00%> (ø)
lib/evmone/instructions.hpp 100.00% <100.00%> (ø)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@chfast chfast changed the title evm: Push integers to the stack word by word evm: Push 64-bit values to the stack without a temporary Nov 1, 2026
GCC 15 and 16 compile stack.push() of an integer by building the
uint256 temporary in a stack slot and copying it to the EVM stack: 3
stores, 2 loads and 2 more stores instead of the 4 stores GCC 14 and
Clang emit. This slows down PC, GAS, CALLDATASIZE, RETURNDATASIZE,
MSIZE and the other instructions pushing an integer: CodSpeed measures
them up to 20% slower with GCC 15 than with GCC 14.

Add a push() overload for uint64_t which assigns the value to the
stack slot, so GCC 15 and 16 compile these instructions as GCC 14
does. The two pushes of int64_t values, GAS and PC in Advanced, now
cast explicitly instead of relying on the conversion to uint256.
@chfast
chfast changed the base branch from ci/codspeed-gcc15 to master November 1, 2026 20:13
@chfast
chfast merged commit f73ca77 into master Nov 1, 2026
26 of 29 checks passed
@chfast
chfast deleted the evm/push-uint64 branch November 1, 2026 20:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant