Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[DO NOT MERGE; EOF] Draft of some experiments with libevmasm optimizer for EOF #15921

Closed
wants to merge 5 commits into from

Conversation

ekpyron
Copy link
Member

@ekpyron ekpyron commented Mar 11, 2025

This is NOT anywhere near ready for actual merging. I just played around with this as a proof of concept for bringing back most libevmasm optimizers at least in a very simple and limited fashion (like deduplicating only reverting code paths within the same code section; constant optimization without using codecopy etc).

The more significant ones, the low-level inliner and the CSE would require even more doing.

But it gives us a lower bound for an estimate of how much savings we can still expect - this is what I get on top of the current EOF implementation with this draft (apart from a hand full of tests that start failing due to validation errors):
Notably, it's double digit percentage points for ERC20 contracts in our test suite; 5% for the deposit contract; etc.

We should emphasize this with our upcoming release (the final optimal version will even supersede these numbers by quite a bit).

Note that this is savings on top of the base-line unoptimized EOF savings, which will already be in the release (despite occasional code size regressions).

Change with these optimizations on top of the current EOF implementation:

Click for a table of gas differences
File name IR optimized Legacy optimized Legacy
array/dynamic_arrays_in_storage.sol +0%
array/copying/array_of_struct_calldata_to_storage.sol +0%
array/copying/array_of_struct_memory_to_storage.sol +0%
array/copying/array_of_structs_containing_arrays_memory_to_storage.sol +0%
array/dynamic_multi_array_cleanup.sol +0%
storageLayoutSpecifier/delete.sol +0%
array/copying/array_copy_target_simple.sol +0%
array/nested_calldata_storage2.sol +0%
various/different_call_type_transient.sol -0%
inlineAssembly/transient_storage_low_level_calls.sol -0%
array/copying/array_copy_storage_storage_dyn_dyn.sol -0%
storageLayoutSpecifier/multiple_inheritance.sol -0%
storageLayoutSpecifier/state_variable_mapping.sol -0%
array/copying/array_copy_storage_storage_static_static.sol -0%
structs/struct_copy_via_local.sol -0%
storageLayoutSpecifier/state_variable_dynamic_array.sol -0%
structs/struct_copy.sol -0%
array/copying/copy_removes_bytes_data.sol -0%
array/copying/bytes_inside_mappings.sol -0%
array/nested_calldata_storage.sol -0%
array/copying/calldata_array_dynamic_to_storage.sol -0%
array/copying/array_copy_storage_storage_static_dynamic.sol -0%
calldata/copy_from_calldata_removes_bytes_data.sol -0%
structs/struct_containing_bytes_copy_and_delete.sol -0%
array/bytes_length_member.sol -0%
various/skip_dynamic_types_for_structs.sol -0%
abiEncodeDecode/abi_decode_simple_storage.sol -0%
abiEncoderV2/calldata_overlapped_dynamic_arrays.sol -0%
array/copying/array_copy_storage_storage_dynamic_dynamic.sol -0%
array/copying/storage_memory_nested_bytes.sol -0%
array/dynamic_array_cleanup.sol -0%
structs/struct_memory_to_storage_function_ptr.sol -0%
array/copying/array_copy_nested_array.sol -0%
libraries/using_library_mappings_return.sol -0%
array/copying/storage_memory_nested_struct.sol -0%
storage/empty_nonempty_empty.sol -0%
array/fixed_array_cleanup.sol -0%
array/copying/array_copy_storage_to_memory_nested.sol -0%
storage/packed_storage_structs_bytes.sol -0%
structs/calldata/calldata_struct_with_nested_array_to_storage.sol -0%
array/copying/copying_bytes_multiassign.sol -0%
array/copying/array_copy_calldata_storage.sol -0%
array/push/array_push.sol -0%
abiEncoderV2/abi_encode_v2.sol -0%
array/copying/array_copy_target_simple_2.sol -0%
array/copying/array_copy_storage_storage_different_base.sol -0%
array/copying/array_nested_calldata_to_storage.sol -0%
array/copying/array_to_mapping.sol -0%
abiEncoderV2/storage_array_encoding.sol -0%
array/copying/storage_memory_nested_from_pointer.sol -0%
array/copying/storage_memory_nested.sol -0%
array/push/array_push_nested_from_calldata.sol -0%
storageLayoutSpecifier/storage_reference_array.sol -0%
abiEncoderV1/abi_decode_v2_storage.sol -0%
viaYul/copy_struct_invalid_ir_bug.sol -0%
events/event_dynamic_nested_array_storage_v2.sol -0%
array/copying/nested_array_element_storage_to_storage.sol -0%
structs/copy_substructures_from_mapping.sol -0%
array/copying/array_of_function_external_storage_to_storage_dynamic_different_mutability.sol -0%
array/copying/array_elements_to_mapping.sol -0%
structs/copy_from_mapping.sol -0%
array/push/nested_bytes_push.sol -0%
array/copying/calldata_array_to_mapping.sol -0%
types/mapping/copy_from_mapping_to_mapping.sol -0%
array/copying/nested_array_of_structs_storage_to_storage.sol -0%
structs/copy_to_mapping.sol -0%
structs/copy_substructures_to_mapping.sol -0%
array/copying/nested_dynamic_array_element_calldata_to_storage.sol -0%
storageLayoutSpecifier/dynamic_array_storage_end.sol -0%
structs/copy_struct_array_from_storage.sol -0%
abiEncoderV1/struct/struct_storage_ptr.sol -0%
array/copying/copy_byte_array_to_storage.sol -0%
structs/struct_delete_storage_with_array.sol -0%
array/copying/array_of_function_external_storage_to_storage_dynamic.sol -0%
structs/memory_structs_nested_load.sol -0%
array/push/array_push_struct_from_calldata.sol -0%
array/copying/copy_byte_array_in_struct_to_storage.sol -0%
array/copying/array_copy_including_array.sol -0%
array/array_storage_index_access.sol -0%
array/copying/elements_of_nested_array_of_structs_calldata_to_storage.sol -0%
array/copying/array_of_structs_containing_arrays_calldata_to_storage.sol -0%
array/copying/nested_array_of_structs_calldata_to_storage.sol -0%
array/copying/array_copy_different_packing.sol -0%
array/push/array_push_struct.sol -0%
array/copying/elements_of_nested_array_of_structs_memory_to_storage.sol -0%
array/copying/copy_function_internal_storage_array.sol -0%
array/copying/array_nested_memory_to_storage.sol -0%
various/destructuring_assignment.sol -0%
events/event_dynamic_array_storage_v2.sol -0%
events/event_dynamic_array_storage.sol -0%
array/copying/array_copy_clear_storage.sol -0%
array/pop/array_pop_array_transition.sol -0%
functionCall/mapping_array_internal_argument.sol -0%
array/copying/nested_array_of_structs_memory_to_storage.sol -0%
array/arrays_complex_from_and_to_storage.sol -0%
array/copying/array_copy_storage_storage_struct.sol -0%
array/array_storage_index_zeroed_test.sol -0%
array/copying/array_storage_multi_items_per_slot.sol -0%
array/copying/array_copy_storage_storage_different_base_nested.sol -0%
array/pop/byte_array_pop_masking_long.sol -0%
storageLayoutSpecifier/mapping_storage_end.sol -0%
array/array_storage_push_empty.sol -0%
array/array_storage_push_pop.sol -0%
array/copying/memory_dyn_2d_bytes_to_storage.sol -0%
array/copying/array_copy_cleanup_uint40.sol -0%
structs/conversion/recursive_storage_memory.sol -0%
externalContracts/snark.sol -0%
libraries/internal_types_in_library.sol -1%
array/push/push_no_args_2d.sol -1%
array/pop/array_pop_uint24_transition.sol -1%
errors/small_error_optimization.sol -1%
various/eof/create_calldata.sol -1%
events/event_indexed_string.sol -1%
array/copying/storage_memory_packed_dyn.sol -1%
array/pop/array_pop_uint16_transition.sol -1%
array/pop/byte_array_pop_long_storage_empty_garbage_ref.sol -1%
array/delete/bytes_delete_element.sol -1%
array/reusing_memory.sol -1%
constructor/bytes_in_constructors_unpacker.sol -1%
array/copying/bytes_storage_to_storage.sol -1%
saltedCreate/eof/salted_create_with_value.sol -1%
array/push/push_no_args_bytes.sol -1%
abiEncoderV2/abi_encode_calldata_slice.sol -1%
abiEncoderV1/abi_encode_calldata_slice.sol -1%
constructor/arrays_in_constructors.sol -2%
array/push/byte_array_push_transition.sol -2%
array/byte_array_transitional_2.sol -2%
array/pop/byte_array_pop_long_storage_empty.sol -2%
immutable/multi_creation.sol -2%
functionCall/creation_function_call_with_salt.sol -2%
functionCall/creation_function_call_with_args.sol -2%
constructor/constructor_static_array_argument.sol -2%
array/constant_var_as_array_length.sol -2%
various/senders_balance.sol -2%
array/copying/cleanup_during_multi_element_per_slot_copy.sol -2%
constructor/bytes_in_constructors_packer.sol -2%
immutable/immutable_tag_too_large_bug.sol -3%
operators/userDefined/operator_making_view_external_call.sol -3%
operators/userDefined/operator_making_pure_external_call.sol -3%
inheritance/inherited_function_calldata_memory_interface.sol -3%
inheritance/value_for_constructor.sol -4%
cleanup/byte_array_to_storage_cleanup.sol -4%
abiEncoderV2/abi_encode_v2_in_function_inherited_in_v1_contract.sol -4%
externalContracts/strings.sol -5%
externalContracts/deposit_contract.sol -5%
functionCall/eof/external_call_to_nonexisting.sol -5%
externalContracts/base64.sol -5%
externalContracts/prbmath_unsigned.sol -5%
array/fixed_arrays_as_return_type.sol -6%
externalContracts/prbmath_signed.sol -6%
externalContracts/FixedFeeRegistrar.sol -7%
array/function_array_cross_calls.sol -8%
functionCall/failed_create.sol -8%
inheritance/constructor_with_params_diamond_inheritance.sol -9%
various/erc20.sol -11%
array/create_memory_array.sol -12%
userDefinedValueType/erc20.sol -12%
externalContracts/ramanujan_pi.sol -21%

Below are the numbers in total that I'm seeing relative to legacy on develop (i.e. current legacy EVM compared to EOF plus these initial improved optimizations). That still has some regressions - I'd assume due to code size increases in artifically small test contracts due to the EOF header overhead (and lack of full deduplication even with this PR) - but other than that impressive improvements.

Click for a table of gas differences
File name IR optimized Legacy optimized Legacy
various/many_subassemblies.sol 11%
constructor/no_callvalue_check.sol 9%
abiEncoderV2/abi_encode_v2_in_function_inherited_in_v1_contract.sol 5%
immutable/multi_creation.sol 4%
inheritance/inherited_function_calldata_memory_interface.sol 2%
array/reusing_memory.sol 2%
libraries/internal_types_in_library.sol 1%
array/copying/array_storage_multi_items_per_slot.sol 1%
functionCall/mapping_array_internal_argument.sol +0%
array/copying/array_of_struct_memory_to_storage.sol +0%
constructor/bytes_in_constructors_packer.sol +0%
structs/structs.sol +0%
libraries/using_library_mappings_return.sol +0%
structs/memory_structs_nested_load.sol +0%
storageLayoutSpecifier/state_variable_mapping.sol +0%
events/event_dynamic_array_storage_v2.sol +0%
events/event_dynamic_array_storage.sol +0%
constructor/arrays_in_constructors.sol +0%
array/copying/array_copy_storage_storage_different_base_nested.sol +0%
structs/struct_copy.sol +0%
saltedCreate/salted_create.sol +0%
inlineAssembly/transient_storage_low_level_calls.sol +0%
various/eof/create_calldata.sol
saltedCreate/eof/salted_create_with_value.sol
inlineAssembly/tstore_hidden_staticcall.sol -0%
various/different_call_type_transient.sol -0%
various/staticcall_for_view_and_pure.sol -0%
structs/struct_copy_via_local.sol -0%
array/copying/array_copy_clear_storage.sol -0%
storageLayoutSpecifier/multiple_inheritance.sol -0%
various/swap_in_storage_overwrite.sol -0%
structs/struct_memory_to_storage_function_ptr.sol -0%
array/copying/array_copy_storage_storage_dynamic_dynamic.sol -0%
array/push/array_push.sol -0%
structs/struct_delete_storage_with_array.sol -0%
array/fixed_array_cleanup.sol -0%
array/copying/copy_removes_bytes_data.sol -0%
array/nested_calldata_storage.sol -0%
array/nested_calldata_storage2.sol -0%
abiEncoderV1/struct/struct_storage_ptr.sol -0%
array/copying/array_copy_target_simple.sol -0%
storageLayoutSpecifier/state_variable_dynamic_array.sol -0%
array/copying/array_copy_storage_storage_different_base.sol -0%
array/copying/bytes_inside_mappings.sol -0%
calldata/copy_from_calldata_removes_bytes_data.sol -0%
array/copying/array_copy_target_simple_2.sol -0%
structs/struct_containing_bytes_copy_and_delete.sol -0%
array/copying/storage_memory_nested_from_pointer.sol -0%
array/copying/storage_memory_nested.sol -0%
storageLayoutSpecifier/delete.sol -0%
abiEncoderV2/abi_encode_v2.sol -0%
array/copying/array_copy_calldata_storage.sol -0%
array/bytes_length_member.sol -0%
array/copying/array_copy_storage_storage_static_dynamic.sol -0%
events/event_dynamic_nested_array_storage_v2.sol -0%
array/copying/array_copy_storage_storage_dyn_dyn.sol -0%
storage/packed_storage_structs_bytes.sol -0%
storage/empty_nonempty_empty.sol -0%
array/push/array_push_struct.sol -0%
structs/copy_struct_array_from_storage.sol -0%
array/copying/nested_array_of_structs_storage_to_storage.sol -0%
various/skip_dynamic_types_for_structs.sol -0%
array/copying/calldata_array_dynamic_to_storage.sol -0%
array/copying/array_of_function_external_storage_to_storage_dynamic_different_mutability.sol -0%
storageLayoutSpecifier/mapping_storage_end.sol -0%
structs/calldata/calldata_struct_with_nested_array_to_storage.sol -0%
array/copying/array_copy_nested_array.sol -0%
array/dynamic_array_cleanup.sol -0%
array/copying/copying_bytes_multiassign.sol -0%
array/copying/storage_memory_nested_bytes.sol -0%
array/push/nested_bytes_push.sol -0%
array/copying/nested_array_element_storage_to_storage.sol -0%
abiEncoderV2/storage_array_encoding.sol -0%
abiEncoderV2/calldata_overlapped_dynamic_arrays.sol -0%
array/copying/array_nested_calldata_to_storage.sol -0%
array/push/array_push_struct_from_calldata.sol -0%
array/copying/array_of_function_external_storage_to_storage_dynamic.sol -0%
array/copying/storage_memory_nested_struct.sol -0%
array/invalid_encoding_for_storage_byte_array.sol -0%
array/push/array_push_nested_from_calldata.sol -0%
array/copying/array_copy_different_packing.sol -0%
array/copying/array_copy_storage_storage_static_static.sol -0%
array/copying/array_of_struct_calldata_to_storage.sol -0%
array/copying/array_copy_storage_to_memory_nested.sol -0%
array/copying/copy_function_internal_storage_array.sol -0%
various/destructuring_assignment.sol -0%
array/copying/array_copy_storage_storage_struct.sol -0%
array/copying/array_nested_memory_to_storage.sol -0%
abiEncodeDecode/abi_decode_simple_storage.sol -0%
storageLayoutSpecifier/storage_reference_array.sol -0%
abiEncoderV1/abi_decode_v2_storage.sol -0%
viaYul/copy_struct_invalid_ir_bug.sol -1%
array/copying/copy_byte_array_to_storage.sol -1%
structs/copy_from_mapping.sol -1%
array/copying/copy_byte_array_in_struct_to_storage.sol -1%
array/pop/array_pop_array_transition.sol -1%
structs/copy_substructures_from_mapping.sol -1%
array/dynamic_multi_array_cleanup.sol -1%
storageLayoutSpecifier/dynamic_array_storage_end.sol -1%
structs/copy_substructures_to_mapping.sol -1%
operators/userDefined/operator_making_view_external_call.sol -1%
operators/userDefined/operator_making_pure_external_call.sol -1%
array/copying/nested_dynamic_array_element_calldata_to_storage.sol -1%
structs/copy_to_mapping.sol -1%
types/mapping/copy_from_mapping_to_mapping.sol -1%
array/copying/array_of_structs_containing_arrays_memory_to_storage.sol -1%
libraries/using_library_mappings_public.sol -1%
array/arrays_complex_from_and_to_storage.sol -1%
errors/small_error_optimization.sol -1%
array/copying/array_to_mapping.sol -1%
array/copying/array_copy_cleanup_uint40.sol -1%
array/array_storage_index_zeroed_test.sol -1%
array/array_storage_index_access.sol -1%
array/copying/array_of_structs_containing_arrays_calldata_to_storage.sol -1%
array/copying/calldata_array_to_mapping.sol -1%
array/copying/array_elements_to_mapping.sol -1%
array/copying/elements_of_nested_array_of_structs_calldata_to_storage.sol -1%
array/copying/nested_array_of_structs_calldata_to_storage.sol -1%
array/copying/function_type_array_to_storage.sol -1%
userDefinedValueType/calldata.sol -1%
array/copying/array_copy_including_array.sol -1%
array/copying/storage_memory_packed_dyn.sol -1%
array/copying/elements_of_nested_array_of_structs_memory_to_storage.sol -2%
array/copying/nested_array_of_structs_memory_to_storage.sol -2%
externalContracts/ramanujan_pi.sol -2%
array/pop/array_pop_uint24_transition.sol -3%
array/function_array_cross_calls.sol -3%
externalContracts/snark.sol -3%
structs/conversion/recursive_storage_memory.sol -3%
array/copying/memory_dyn_2d_bytes_to_storage.sol -3%
array/array_storage_push_pop.sol -4%
array/array_storage_push_empty.sol -4%
array/pop/byte_array_pop_masking_long.sol -4%
array/pop/array_pop_uint16_transition.sol -4%
array/dynamic_arrays_in_storage.sol -4%
array/fixed_arrays_as_return_type.sol -4%
externalContracts/deposit_contract.sol -5%
array/push/push_no_args_2d.sol -6%
array/push/push_no_args_bytes.sol -6%
array/delete/bytes_delete_element.sol -6%
events/event_indexed_string.sol -6%
array/pop/byte_array_pop_long_storage_empty_garbage_ref.sol -8%
array/push/byte_array_push_transition.sol -9%
array/byte_array_transitional_2.sol -9%
externalContracts/FixedFeeRegistrar.sol -10%
array/pop/byte_array_pop_long_storage_empty.sol -10%
array/copying/cleanup_during_multi_element_per_slot_copy.sol -10%
array/array_storage_index_boundary_test.sol -10%
array/copying/bytes_storage_to_storage.sol -11%
array/array_storage_length_access.sol -12%
array/array_storage_push_empty_length_address.sol -12%
userDefinedValueType/erc20.sol -14%
externalContracts/prbmath_signed.sol -16%
externalContracts/prbmath_unsigned.sol -16%
various/erc20.sol -17%
array/create_memory_array.sol -17%
inheritance/value_for_constructor.sol -18%
constructor/bytes_in_constructors_unpacker.sol -19%
functionCall/creation_function_call_with_args.sol -20%
functionCall/creation_function_call_with_salt.sol -20%
constructor/constructor_static_array_argument.sol -20%
cleanup/byte_array_to_storage_cleanup.sol -20%
various/senders_balance.sol -21%
functionCall/eof/external_call_to_nonexisting.sol -22%
inheritance/constructor_with_params_diamond_inheritance.sol -22%
storageLayoutSpecifier/constructor.sol -24%
array/constant_var_as_array_length.sol -24%
externalContracts/base64.sol -29%
abiEncoderV2/abi_encode_calldata_slice.sol -34%
abiEncoderV1/abi_encode_calldata_slice.sol -34%
externalContracts/strings.sol -34%
functionCall/failed_create.sol -38%
immutable/immutable_tag_too_large_bug.sol -48%

ekpyron added 5 commits March 11, 2025 05:16
Looses one test case:

semanticTests/array/invalid_encoding_for_storage_byte_array.sol
Looses another handful of tests. Needs to check for correctness (in some version one test expectation actually changed, i.e. it produced invalid output).
This, of course, comes with runtime gas cost regressions.
@ekpyron ekpyron changed the title [DO NOT MERGE] Draft of some experiments with libevmasm optimizer for EOF [DO NOT MERGE; EOF] Draft of some experiments with libevmasm optimizer for EOF Mar 11, 2025
Copy link

This pull request is stale because it has been open for 14 days with no activity.
It will be closed in 7 days unless the stale label is removed.

@github-actions github-actions bot added the stale The issue/PR was marked as stale because it has been open for too long. label Mar 26, 2025
Copy link

github-actions bot commented Apr 2, 2025

This pull request was closed due to a lack of activity for 7 days after it was stale.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
closed-due-inactivity stale The issue/PR was marked as stale because it has been open for too long.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant