[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
codecopyetc).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.solarray/copying/array_of_struct_calldata_to_storage.solarray/copying/array_of_struct_memory_to_storage.solarray/copying/array_of_structs_containing_arrays_memory_to_storage.solarray/dynamic_multi_array_cleanup.solstorageLayoutSpecifier/delete.solarray/copying/array_copy_target_simple.solarray/nested_calldata_storage2.solvarious/different_call_type_transient.solinlineAssembly/transient_storage_low_level_calls.solarray/copying/array_copy_storage_storage_dyn_dyn.solstorageLayoutSpecifier/multiple_inheritance.solstorageLayoutSpecifier/state_variable_mapping.solarray/copying/array_copy_storage_storage_static_static.solstructs/struct_copy_via_local.solstorageLayoutSpecifier/state_variable_dynamic_array.solstructs/struct_copy.solarray/copying/copy_removes_bytes_data.solarray/copying/bytes_inside_mappings.solarray/nested_calldata_storage.solarray/copying/calldata_array_dynamic_to_storage.solarray/copying/array_copy_storage_storage_static_dynamic.solcalldata/copy_from_calldata_removes_bytes_data.solstructs/struct_containing_bytes_copy_and_delete.solarray/bytes_length_member.solvarious/skip_dynamic_types_for_structs.solabiEncodeDecode/abi_decode_simple_storage.solabiEncoderV2/calldata_overlapped_dynamic_arrays.solarray/copying/array_copy_storage_storage_dynamic_dynamic.solarray/copying/storage_memory_nested_bytes.solarray/dynamic_array_cleanup.solstructs/struct_memory_to_storage_function_ptr.solarray/copying/array_copy_nested_array.sollibraries/using_library_mappings_return.solarray/copying/storage_memory_nested_struct.solstorage/empty_nonempty_empty.solarray/fixed_array_cleanup.solarray/copying/array_copy_storage_to_memory_nested.solstorage/packed_storage_structs_bytes.solstructs/calldata/calldata_struct_with_nested_array_to_storage.solarray/copying/copying_bytes_multiassign.solarray/copying/array_copy_calldata_storage.solarray/push/array_push.solabiEncoderV2/abi_encode_v2.solarray/copying/array_copy_target_simple_2.solarray/copying/array_copy_storage_storage_different_base.solarray/copying/array_nested_calldata_to_storage.solarray/copying/array_to_mapping.solabiEncoderV2/storage_array_encoding.solarray/copying/storage_memory_nested_from_pointer.solarray/copying/storage_memory_nested.solarray/push/array_push_nested_from_calldata.solstorageLayoutSpecifier/storage_reference_array.solabiEncoderV1/abi_decode_v2_storage.solviaYul/copy_struct_invalid_ir_bug.solevents/event_dynamic_nested_array_storage_v2.solarray/copying/nested_array_element_storage_to_storage.solstructs/copy_substructures_from_mapping.solarray/copying/array_of_function_external_storage_to_storage_dynamic_different_mutability.solarray/copying/array_elements_to_mapping.solstructs/copy_from_mapping.solarray/push/nested_bytes_push.solarray/copying/calldata_array_to_mapping.soltypes/mapping/copy_from_mapping_to_mapping.solarray/copying/nested_array_of_structs_storage_to_storage.solstructs/copy_to_mapping.solstructs/copy_substructures_to_mapping.solarray/copying/nested_dynamic_array_element_calldata_to_storage.solstorageLayoutSpecifier/dynamic_array_storage_end.solstructs/copy_struct_array_from_storage.solabiEncoderV1/struct/struct_storage_ptr.solarray/copying/copy_byte_array_to_storage.solstructs/struct_delete_storage_with_array.solarray/copying/array_of_function_external_storage_to_storage_dynamic.solstructs/memory_structs_nested_load.solarray/push/array_push_struct_from_calldata.solarray/copying/copy_byte_array_in_struct_to_storage.solarray/copying/array_copy_including_array.solarray/array_storage_index_access.solarray/copying/elements_of_nested_array_of_structs_calldata_to_storage.solarray/copying/array_of_structs_containing_arrays_calldata_to_storage.solarray/copying/nested_array_of_structs_calldata_to_storage.solarray/copying/array_copy_different_packing.solarray/push/array_push_struct.solarray/copying/elements_of_nested_array_of_structs_memory_to_storage.solarray/copying/copy_function_internal_storage_array.solarray/copying/array_nested_memory_to_storage.solvarious/destructuring_assignment.solevents/event_dynamic_array_storage_v2.solevents/event_dynamic_array_storage.solarray/copying/array_copy_clear_storage.solarray/pop/array_pop_array_transition.solfunctionCall/mapping_array_internal_argument.solarray/copying/nested_array_of_structs_memory_to_storage.solarray/arrays_complex_from_and_to_storage.solarray/copying/array_copy_storage_storage_struct.solarray/array_storage_index_zeroed_test.solarray/copying/array_storage_multi_items_per_slot.solarray/copying/array_copy_storage_storage_different_base_nested.solarray/pop/byte_array_pop_masking_long.solstorageLayoutSpecifier/mapping_storage_end.solarray/array_storage_push_empty.solarray/array_storage_push_pop.solarray/copying/memory_dyn_2d_bytes_to_storage.solarray/copying/array_copy_cleanup_uint40.solstructs/conversion/recursive_storage_memory.solexternalContracts/snark.sollibraries/internal_types_in_library.solarray/push/push_no_args_2d.solarray/pop/array_pop_uint24_transition.solerrors/small_error_optimization.solvarious/eof/create_calldata.solevents/event_indexed_string.solarray/copying/storage_memory_packed_dyn.solarray/pop/array_pop_uint16_transition.solarray/pop/byte_array_pop_long_storage_empty_garbage_ref.solarray/delete/bytes_delete_element.solarray/reusing_memory.solconstructor/bytes_in_constructors_unpacker.solarray/copying/bytes_storage_to_storage.solsaltedCreate/eof/salted_create_with_value.solarray/push/push_no_args_bytes.solabiEncoderV2/abi_encode_calldata_slice.solabiEncoderV1/abi_encode_calldata_slice.solconstructor/arrays_in_constructors.solarray/push/byte_array_push_transition.solarray/byte_array_transitional_2.solarray/pop/byte_array_pop_long_storage_empty.solimmutable/multi_creation.solfunctionCall/creation_function_call_with_salt.solfunctionCall/creation_function_call_with_args.solconstructor/constructor_static_array_argument.solarray/constant_var_as_array_length.solvarious/senders_balance.solarray/copying/cleanup_during_multi_element_per_slot_copy.solconstructor/bytes_in_constructors_packer.solimmutable/immutable_tag_too_large_bug.soloperators/userDefined/operator_making_view_external_call.soloperators/userDefined/operator_making_pure_external_call.solinheritance/inherited_function_calldata_memory_interface.solinheritance/value_for_constructor.solcleanup/byte_array_to_storage_cleanup.solabiEncoderV2/abi_encode_v2_in_function_inherited_in_v1_contract.solexternalContracts/strings.solexternalContracts/deposit_contract.solfunctionCall/eof/external_call_to_nonexisting.solexternalContracts/base64.solexternalContracts/prbmath_unsigned.solarray/fixed_arrays_as_return_type.solexternalContracts/prbmath_signed.solexternalContracts/FixedFeeRegistrar.solarray/function_array_cross_calls.solfunctionCall/failed_create.solinheritance/constructor_with_params_diamond_inheritance.solvarious/erc20.solarray/create_memory_array.soluserDefinedValueType/erc20.solexternalContracts/ramanujan_pi.solBelow 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.solconstructor/no_callvalue_check.solabiEncoderV2/abi_encode_v2_in_function_inherited_in_v1_contract.solimmutable/multi_creation.solinheritance/inherited_function_calldata_memory_interface.solarray/reusing_memory.sollibraries/internal_types_in_library.solarray/copying/array_storage_multi_items_per_slot.solfunctionCall/mapping_array_internal_argument.solarray/copying/array_of_struct_memory_to_storage.solconstructor/bytes_in_constructors_packer.solstructs/structs.sollibraries/using_library_mappings_return.solstructs/memory_structs_nested_load.solstorageLayoutSpecifier/state_variable_mapping.solevents/event_dynamic_array_storage_v2.solevents/event_dynamic_array_storage.solconstructor/arrays_in_constructors.solarray/copying/array_copy_storage_storage_different_base_nested.solstructs/struct_copy.solsaltedCreate/salted_create.solinlineAssembly/transient_storage_low_level_calls.solvarious/eof/create_calldata.solsaltedCreate/eof/salted_create_with_value.solinlineAssembly/tstore_hidden_staticcall.solvarious/different_call_type_transient.solvarious/staticcall_for_view_and_pure.solstructs/struct_copy_via_local.solarray/copying/array_copy_clear_storage.solstorageLayoutSpecifier/multiple_inheritance.solvarious/swap_in_storage_overwrite.solstructs/struct_memory_to_storage_function_ptr.solarray/copying/array_copy_storage_storage_dynamic_dynamic.solarray/push/array_push.solstructs/struct_delete_storage_with_array.solarray/fixed_array_cleanup.solarray/copying/copy_removes_bytes_data.solarray/nested_calldata_storage.solarray/nested_calldata_storage2.solabiEncoderV1/struct/struct_storage_ptr.solarray/copying/array_copy_target_simple.solstorageLayoutSpecifier/state_variable_dynamic_array.solarray/copying/array_copy_storage_storage_different_base.solarray/copying/bytes_inside_mappings.solcalldata/copy_from_calldata_removes_bytes_data.solarray/copying/array_copy_target_simple_2.solstructs/struct_containing_bytes_copy_and_delete.solarray/copying/storage_memory_nested_from_pointer.solarray/copying/storage_memory_nested.solstorageLayoutSpecifier/delete.solabiEncoderV2/abi_encode_v2.solarray/copying/array_copy_calldata_storage.solarray/bytes_length_member.solarray/copying/array_copy_storage_storage_static_dynamic.solevents/event_dynamic_nested_array_storage_v2.solarray/copying/array_copy_storage_storage_dyn_dyn.solstorage/packed_storage_structs_bytes.solstorage/empty_nonempty_empty.solarray/push/array_push_struct.solstructs/copy_struct_array_from_storage.solarray/copying/nested_array_of_structs_storage_to_storage.solvarious/skip_dynamic_types_for_structs.solarray/copying/calldata_array_dynamic_to_storage.solarray/copying/array_of_function_external_storage_to_storage_dynamic_different_mutability.solstorageLayoutSpecifier/mapping_storage_end.solstructs/calldata/calldata_struct_with_nested_array_to_storage.solarray/copying/array_copy_nested_array.solarray/dynamic_array_cleanup.solarray/copying/copying_bytes_multiassign.solarray/copying/storage_memory_nested_bytes.solarray/push/nested_bytes_push.solarray/copying/nested_array_element_storage_to_storage.solabiEncoderV2/storage_array_encoding.solabiEncoderV2/calldata_overlapped_dynamic_arrays.solarray/copying/array_nested_calldata_to_storage.solarray/push/array_push_struct_from_calldata.solarray/copying/array_of_function_external_storage_to_storage_dynamic.solarray/copying/storage_memory_nested_struct.solarray/invalid_encoding_for_storage_byte_array.solarray/push/array_push_nested_from_calldata.solarray/copying/array_copy_different_packing.solarray/copying/array_copy_storage_storage_static_static.solarray/copying/array_of_struct_calldata_to_storage.solarray/copying/array_copy_storage_to_memory_nested.solarray/copying/copy_function_internal_storage_array.solvarious/destructuring_assignment.solarray/copying/array_copy_storage_storage_struct.solarray/copying/array_nested_memory_to_storage.solabiEncodeDecode/abi_decode_simple_storage.solstorageLayoutSpecifier/storage_reference_array.solabiEncoderV1/abi_decode_v2_storage.solviaYul/copy_struct_invalid_ir_bug.solarray/copying/copy_byte_array_to_storage.solstructs/copy_from_mapping.solarray/copying/copy_byte_array_in_struct_to_storage.solarray/pop/array_pop_array_transition.solstructs/copy_substructures_from_mapping.solarray/dynamic_multi_array_cleanup.solstorageLayoutSpecifier/dynamic_array_storage_end.solstructs/copy_substructures_to_mapping.soloperators/userDefined/operator_making_view_external_call.soloperators/userDefined/operator_making_pure_external_call.solarray/copying/nested_dynamic_array_element_calldata_to_storage.solstructs/copy_to_mapping.soltypes/mapping/copy_from_mapping_to_mapping.solarray/copying/array_of_structs_containing_arrays_memory_to_storage.sollibraries/using_library_mappings_public.solarray/arrays_complex_from_and_to_storage.solerrors/small_error_optimization.solarray/copying/array_to_mapping.solarray/copying/array_copy_cleanup_uint40.solarray/array_storage_index_zeroed_test.solarray/array_storage_index_access.solarray/copying/array_of_structs_containing_arrays_calldata_to_storage.solarray/copying/calldata_array_to_mapping.solarray/copying/array_elements_to_mapping.solarray/copying/elements_of_nested_array_of_structs_calldata_to_storage.solarray/copying/nested_array_of_structs_calldata_to_storage.solarray/copying/function_type_array_to_storage.soluserDefinedValueType/calldata.solarray/copying/array_copy_including_array.solarray/copying/storage_memory_packed_dyn.solarray/copying/elements_of_nested_array_of_structs_memory_to_storage.solarray/copying/nested_array_of_structs_memory_to_storage.solexternalContracts/ramanujan_pi.solarray/pop/array_pop_uint24_transition.solarray/function_array_cross_calls.solexternalContracts/snark.solstructs/conversion/recursive_storage_memory.solarray/copying/memory_dyn_2d_bytes_to_storage.solarray/array_storage_push_pop.solarray/array_storage_push_empty.solarray/pop/byte_array_pop_masking_long.solarray/pop/array_pop_uint16_transition.solarray/dynamic_arrays_in_storage.solarray/fixed_arrays_as_return_type.solexternalContracts/deposit_contract.solarray/push/push_no_args_2d.solarray/push/push_no_args_bytes.solarray/delete/bytes_delete_element.solevents/event_indexed_string.solarray/pop/byte_array_pop_long_storage_empty_garbage_ref.solarray/push/byte_array_push_transition.solarray/byte_array_transitional_2.solexternalContracts/FixedFeeRegistrar.solarray/pop/byte_array_pop_long_storage_empty.solarray/copying/cleanup_during_multi_element_per_slot_copy.solarray/array_storage_index_boundary_test.solarray/copying/bytes_storage_to_storage.solarray/array_storage_length_access.solarray/array_storage_push_empty_length_address.soluserDefinedValueType/erc20.solexternalContracts/prbmath_signed.solexternalContracts/prbmath_unsigned.solvarious/erc20.solarray/create_memory_array.solinheritance/value_for_constructor.solconstructor/bytes_in_constructors_unpacker.solfunctionCall/creation_function_call_with_args.solfunctionCall/creation_function_call_with_salt.solconstructor/constructor_static_array_argument.solcleanup/byte_array_to_storage_cleanup.solvarious/senders_balance.solfunctionCall/eof/external_call_to_nonexisting.solinheritance/constructor_with_params_diamond_inheritance.solstorageLayoutSpecifier/constructor.solarray/constant_var_as_array_length.solexternalContracts/base64.solabiEncoderV2/abi_encode_calldata_slice.solabiEncoderV1/abi_encode_calldata_slice.solexternalContracts/strings.solfunctionCall/failed_create.solimmutable/immutable_tag_too_large_bug.sol