[DO NOT MERGE; EOF] Draft of some experiments with libevmasm optimizer for EOF #15921
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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
array/dynamic_arrays_in_storage.sol
array/copying/array_of_struct_calldata_to_storage.sol
array/copying/array_of_struct_memory_to_storage.sol
array/copying/array_of_structs_containing_arrays_memory_to_storage.sol
array/dynamic_multi_array_cleanup.sol
storageLayoutSpecifier/delete.sol
array/copying/array_copy_target_simple.sol
array/nested_calldata_storage2.sol
various/different_call_type_transient.sol
inlineAssembly/transient_storage_low_level_calls.sol
array/copying/array_copy_storage_storage_dyn_dyn.sol
storageLayoutSpecifier/multiple_inheritance.sol
storageLayoutSpecifier/state_variable_mapping.sol
array/copying/array_copy_storage_storage_static_static.sol
structs/struct_copy_via_local.sol
storageLayoutSpecifier/state_variable_dynamic_array.sol
structs/struct_copy.sol
array/copying/copy_removes_bytes_data.sol
array/copying/bytes_inside_mappings.sol
array/nested_calldata_storage.sol
array/copying/calldata_array_dynamic_to_storage.sol
array/copying/array_copy_storage_storage_static_dynamic.sol
calldata/copy_from_calldata_removes_bytes_data.sol
structs/struct_containing_bytes_copy_and_delete.sol
array/bytes_length_member.sol
various/skip_dynamic_types_for_structs.sol
abiEncodeDecode/abi_decode_simple_storage.sol
abiEncoderV2/calldata_overlapped_dynamic_arrays.sol
array/copying/array_copy_storage_storage_dynamic_dynamic.sol
array/copying/storage_memory_nested_bytes.sol
array/dynamic_array_cleanup.sol
structs/struct_memory_to_storage_function_ptr.sol
array/copying/array_copy_nested_array.sol
libraries/using_library_mappings_return.sol
array/copying/storage_memory_nested_struct.sol
storage/empty_nonempty_empty.sol
array/fixed_array_cleanup.sol
array/copying/array_copy_storage_to_memory_nested.sol
storage/packed_storage_structs_bytes.sol
structs/calldata/calldata_struct_with_nested_array_to_storage.sol
array/copying/copying_bytes_multiassign.sol
array/copying/array_copy_calldata_storage.sol
array/push/array_push.sol
abiEncoderV2/abi_encode_v2.sol
array/copying/array_copy_target_simple_2.sol
array/copying/array_copy_storage_storage_different_base.sol
array/copying/array_nested_calldata_to_storage.sol
array/copying/array_to_mapping.sol
abiEncoderV2/storage_array_encoding.sol
array/copying/storage_memory_nested_from_pointer.sol
array/copying/storage_memory_nested.sol
array/push/array_push_nested_from_calldata.sol
storageLayoutSpecifier/storage_reference_array.sol
abiEncoderV1/abi_decode_v2_storage.sol
viaYul/copy_struct_invalid_ir_bug.sol
events/event_dynamic_nested_array_storage_v2.sol
array/copying/nested_array_element_storage_to_storage.sol
structs/copy_substructures_from_mapping.sol
array/copying/array_of_function_external_storage_to_storage_dynamic_different_mutability.sol
array/copying/array_elements_to_mapping.sol
structs/copy_from_mapping.sol
array/push/nested_bytes_push.sol
array/copying/calldata_array_to_mapping.sol
types/mapping/copy_from_mapping_to_mapping.sol
array/copying/nested_array_of_structs_storage_to_storage.sol
structs/copy_to_mapping.sol
structs/copy_substructures_to_mapping.sol
array/copying/nested_dynamic_array_element_calldata_to_storage.sol
storageLayoutSpecifier/dynamic_array_storage_end.sol
structs/copy_struct_array_from_storage.sol
abiEncoderV1/struct/struct_storage_ptr.sol
array/copying/copy_byte_array_to_storage.sol
structs/struct_delete_storage_with_array.sol
array/copying/array_of_function_external_storage_to_storage_dynamic.sol
structs/memory_structs_nested_load.sol
array/push/array_push_struct_from_calldata.sol
array/copying/copy_byte_array_in_struct_to_storage.sol
array/copying/array_copy_including_array.sol
array/array_storage_index_access.sol
array/copying/elements_of_nested_array_of_structs_calldata_to_storage.sol
array/copying/array_of_structs_containing_arrays_calldata_to_storage.sol
array/copying/nested_array_of_structs_calldata_to_storage.sol
array/copying/array_copy_different_packing.sol
array/push/array_push_struct.sol
array/copying/elements_of_nested_array_of_structs_memory_to_storage.sol
array/copying/copy_function_internal_storage_array.sol
array/copying/array_nested_memory_to_storage.sol
various/destructuring_assignment.sol
events/event_dynamic_array_storage_v2.sol
events/event_dynamic_array_storage.sol
array/copying/array_copy_clear_storage.sol
array/pop/array_pop_array_transition.sol
functionCall/mapping_array_internal_argument.sol
array/copying/nested_array_of_structs_memory_to_storage.sol
array/arrays_complex_from_and_to_storage.sol
array/copying/array_copy_storage_storage_struct.sol
array/array_storage_index_zeroed_test.sol
array/copying/array_storage_multi_items_per_slot.sol
array/copying/array_copy_storage_storage_different_base_nested.sol
array/pop/byte_array_pop_masking_long.sol
storageLayoutSpecifier/mapping_storage_end.sol
array/array_storage_push_empty.sol
array/array_storage_push_pop.sol
array/copying/memory_dyn_2d_bytes_to_storage.sol
array/copying/array_copy_cleanup_uint40.sol
structs/conversion/recursive_storage_memory.sol
externalContracts/snark.sol
libraries/internal_types_in_library.sol
array/push/push_no_args_2d.sol
array/pop/array_pop_uint24_transition.sol
errors/small_error_optimization.sol
various/eof/create_calldata.sol
events/event_indexed_string.sol
array/copying/storage_memory_packed_dyn.sol
array/pop/array_pop_uint16_transition.sol
array/pop/byte_array_pop_long_storage_empty_garbage_ref.sol
array/delete/bytes_delete_element.sol
array/reusing_memory.sol
constructor/bytes_in_constructors_unpacker.sol
array/copying/bytes_storage_to_storage.sol
saltedCreate/eof/salted_create_with_value.sol
array/push/push_no_args_bytes.sol
abiEncoderV2/abi_encode_calldata_slice.sol
abiEncoderV1/abi_encode_calldata_slice.sol
constructor/arrays_in_constructors.sol
array/push/byte_array_push_transition.sol
array/byte_array_transitional_2.sol
array/pop/byte_array_pop_long_storage_empty.sol
immutable/multi_creation.sol
functionCall/creation_function_call_with_salt.sol
functionCall/creation_function_call_with_args.sol
constructor/constructor_static_array_argument.sol
array/constant_var_as_array_length.sol
various/senders_balance.sol
array/copying/cleanup_during_multi_element_per_slot_copy.sol
constructor/bytes_in_constructors_packer.sol
immutable/immutable_tag_too_large_bug.sol
operators/userDefined/operator_making_view_external_call.sol
operators/userDefined/operator_making_pure_external_call.sol
inheritance/inherited_function_calldata_memory_interface.sol
inheritance/value_for_constructor.sol
cleanup/byte_array_to_storage_cleanup.sol
abiEncoderV2/abi_encode_v2_in_function_inherited_in_v1_contract.sol
externalContracts/strings.sol
externalContracts/deposit_contract.sol
functionCall/eof/external_call_to_nonexisting.sol
externalContracts/base64.sol
externalContracts/prbmath_unsigned.sol
array/fixed_arrays_as_return_type.sol
externalContracts/prbmath_signed.sol
externalContracts/FixedFeeRegistrar.sol
array/function_array_cross_calls.sol
functionCall/failed_create.sol
inheritance/constructor_with_params_diamond_inheritance.sol
various/erc20.sol
array/create_memory_array.sol
userDefinedValueType/erc20.sol
externalContracts/ramanujan_pi.sol
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
various/many_subassemblies.sol
constructor/no_callvalue_check.sol
abiEncoderV2/abi_encode_v2_in_function_inherited_in_v1_contract.sol
immutable/multi_creation.sol
inheritance/inherited_function_calldata_memory_interface.sol
array/reusing_memory.sol
libraries/internal_types_in_library.sol
array/copying/array_storage_multi_items_per_slot.sol
functionCall/mapping_array_internal_argument.sol
array/copying/array_of_struct_memory_to_storage.sol
constructor/bytes_in_constructors_packer.sol
structs/structs.sol
libraries/using_library_mappings_return.sol
structs/memory_structs_nested_load.sol
storageLayoutSpecifier/state_variable_mapping.sol
events/event_dynamic_array_storage_v2.sol
events/event_dynamic_array_storage.sol
constructor/arrays_in_constructors.sol
array/copying/array_copy_storage_storage_different_base_nested.sol
structs/struct_copy.sol
saltedCreate/salted_create.sol
inlineAssembly/transient_storage_low_level_calls.sol
various/eof/create_calldata.sol
saltedCreate/eof/salted_create_with_value.sol
inlineAssembly/tstore_hidden_staticcall.sol
various/different_call_type_transient.sol
various/staticcall_for_view_and_pure.sol
structs/struct_copy_via_local.sol
array/copying/array_copy_clear_storage.sol
storageLayoutSpecifier/multiple_inheritance.sol
various/swap_in_storage_overwrite.sol
structs/struct_memory_to_storage_function_ptr.sol
array/copying/array_copy_storage_storage_dynamic_dynamic.sol
array/push/array_push.sol
structs/struct_delete_storage_with_array.sol
array/fixed_array_cleanup.sol
array/copying/copy_removes_bytes_data.sol
array/nested_calldata_storage.sol
array/nested_calldata_storage2.sol
abiEncoderV1/struct/struct_storage_ptr.sol
array/copying/array_copy_target_simple.sol
storageLayoutSpecifier/state_variable_dynamic_array.sol
array/copying/array_copy_storage_storage_different_base.sol
array/copying/bytes_inside_mappings.sol
calldata/copy_from_calldata_removes_bytes_data.sol
array/copying/array_copy_target_simple_2.sol
structs/struct_containing_bytes_copy_and_delete.sol
array/copying/storage_memory_nested_from_pointer.sol
array/copying/storage_memory_nested.sol
storageLayoutSpecifier/delete.sol
abiEncoderV2/abi_encode_v2.sol
array/copying/array_copy_calldata_storage.sol
array/bytes_length_member.sol
array/copying/array_copy_storage_storage_static_dynamic.sol
events/event_dynamic_nested_array_storage_v2.sol
array/copying/array_copy_storage_storage_dyn_dyn.sol
storage/packed_storage_structs_bytes.sol
storage/empty_nonempty_empty.sol
array/push/array_push_struct.sol
structs/copy_struct_array_from_storage.sol
array/copying/nested_array_of_structs_storage_to_storage.sol
various/skip_dynamic_types_for_structs.sol
array/copying/calldata_array_dynamic_to_storage.sol
array/copying/array_of_function_external_storage_to_storage_dynamic_different_mutability.sol
storageLayoutSpecifier/mapping_storage_end.sol
structs/calldata/calldata_struct_with_nested_array_to_storage.sol
array/copying/array_copy_nested_array.sol
array/dynamic_array_cleanup.sol
array/copying/copying_bytes_multiassign.sol
array/copying/storage_memory_nested_bytes.sol
array/push/nested_bytes_push.sol
array/copying/nested_array_element_storage_to_storage.sol
abiEncoderV2/storage_array_encoding.sol
abiEncoderV2/calldata_overlapped_dynamic_arrays.sol
array/copying/array_nested_calldata_to_storage.sol
array/push/array_push_struct_from_calldata.sol
array/copying/array_of_function_external_storage_to_storage_dynamic.sol
array/copying/storage_memory_nested_struct.sol
array/invalid_encoding_for_storage_byte_array.sol
array/push/array_push_nested_from_calldata.sol
array/copying/array_copy_different_packing.sol
array/copying/array_copy_storage_storage_static_static.sol
array/copying/array_of_struct_calldata_to_storage.sol
array/copying/array_copy_storage_to_memory_nested.sol
array/copying/copy_function_internal_storage_array.sol
various/destructuring_assignment.sol
array/copying/array_copy_storage_storage_struct.sol
array/copying/array_nested_memory_to_storage.sol
abiEncodeDecode/abi_decode_simple_storage.sol
storageLayoutSpecifier/storage_reference_array.sol
abiEncoderV1/abi_decode_v2_storage.sol
viaYul/copy_struct_invalid_ir_bug.sol
array/copying/copy_byte_array_to_storage.sol
structs/copy_from_mapping.sol
array/copying/copy_byte_array_in_struct_to_storage.sol
array/pop/array_pop_array_transition.sol
structs/copy_substructures_from_mapping.sol
array/dynamic_multi_array_cleanup.sol
storageLayoutSpecifier/dynamic_array_storage_end.sol
structs/copy_substructures_to_mapping.sol
operators/userDefined/operator_making_view_external_call.sol
operators/userDefined/operator_making_pure_external_call.sol
array/copying/nested_dynamic_array_element_calldata_to_storage.sol
structs/copy_to_mapping.sol
types/mapping/copy_from_mapping_to_mapping.sol
array/copying/array_of_structs_containing_arrays_memory_to_storage.sol
libraries/using_library_mappings_public.sol
array/arrays_complex_from_and_to_storage.sol
errors/small_error_optimization.sol
array/copying/array_to_mapping.sol
array/copying/array_copy_cleanup_uint40.sol
array/array_storage_index_zeroed_test.sol
array/array_storage_index_access.sol
array/copying/array_of_structs_containing_arrays_calldata_to_storage.sol
array/copying/calldata_array_to_mapping.sol
array/copying/array_elements_to_mapping.sol
array/copying/elements_of_nested_array_of_structs_calldata_to_storage.sol
array/copying/nested_array_of_structs_calldata_to_storage.sol
array/copying/function_type_array_to_storage.sol
userDefinedValueType/calldata.sol
array/copying/array_copy_including_array.sol
array/copying/storage_memory_packed_dyn.sol
array/copying/elements_of_nested_array_of_structs_memory_to_storage.sol
array/copying/nested_array_of_structs_memory_to_storage.sol
externalContracts/ramanujan_pi.sol
array/pop/array_pop_uint24_transition.sol
array/function_array_cross_calls.sol
externalContracts/snark.sol
structs/conversion/recursive_storage_memory.sol
array/copying/memory_dyn_2d_bytes_to_storage.sol
array/array_storage_push_pop.sol
array/array_storage_push_empty.sol
array/pop/byte_array_pop_masking_long.sol
array/pop/array_pop_uint16_transition.sol
array/dynamic_arrays_in_storage.sol
array/fixed_arrays_as_return_type.sol
externalContracts/deposit_contract.sol
array/push/push_no_args_2d.sol
array/push/push_no_args_bytes.sol
array/delete/bytes_delete_element.sol
events/event_indexed_string.sol
array/pop/byte_array_pop_long_storage_empty_garbage_ref.sol
array/push/byte_array_push_transition.sol
array/byte_array_transitional_2.sol
externalContracts/FixedFeeRegistrar.sol
array/pop/byte_array_pop_long_storage_empty.sol
array/copying/cleanup_during_multi_element_per_slot_copy.sol
array/array_storage_index_boundary_test.sol
array/copying/bytes_storage_to_storage.sol
array/array_storage_length_access.sol
array/array_storage_push_empty_length_address.sol
userDefinedValueType/erc20.sol
externalContracts/prbmath_signed.sol
externalContracts/prbmath_unsigned.sol
various/erc20.sol
array/create_memory_array.sol
inheritance/value_for_constructor.sol
constructor/bytes_in_constructors_unpacker.sol
functionCall/creation_function_call_with_args.sol
functionCall/creation_function_call_with_salt.sol
constructor/constructor_static_array_argument.sol
cleanup/byte_array_to_storage_cleanup.sol
various/senders_balance.sol
functionCall/eof/external_call_to_nonexisting.sol
inheritance/constructor_with_params_diamond_inheritance.sol
storageLayoutSpecifier/constructor.sol
array/constant_var_as_array_length.sol
externalContracts/base64.sol
abiEncoderV2/abi_encode_calldata_slice.sol
abiEncoderV1/abi_encode_calldata_slice.sol
externalContracts/strings.sol
functionCall/failed_create.sol
immutable/immutable_tag_too_large_bug.sol