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

Remove inlining constraint for large functions when targetting the new code transform. #12731

Merged
merged 3 commits into from
May 23, 2022

Conversation

ekpyron
Copy link
Member

@ekpyron ekpyron commented Mar 2, 2022

Depends on #12937.

Changelog.md Outdated
@@ -5,6 +5,7 @@ Language Features:

Compiler Features:
* JSON-AST: Added selector field for errors and events.
* Yul Optimizer: Improve inlining heauristics for via IR code generation and pure Yul compilation.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* Yul Optimizer: Improve inlining heauristics for via IR code generation and pure Yul compilation.
* Yul Optimizer: Improve inlining heuristic for via IR code generation and pure Yul compilation.

mstore(add(add(headStart, length), 96), 0)
}
tail := add(add(headStart, and(add(length, 31), not(31))), 96)
}
function panic_error_0x32()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does it not inline those?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apparently it has a code size of at least 6 and thereby generally doesn't qualify...

@@ -57,6 +57,24 @@
// let a_56 := b_54
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this test still meaningful?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nope, but we may want to run it in a setup that'll go through the old code transform...

@ekpyron
Copy link
Member Author

ekpyron commented Mar 2, 2022

On our tests we get this. But more curious about the external test stats. Even more so since they distinguish code size from gas cost better.

Click for a table of gas differences
File name IR-optimized (%) Legacy-Optimized (%) Legacy (%)
constructor_with_params_inheritance.sol -0.186633 0 0
constructor_with_params.sol -0.094985 0 0
constructor_with_params_diamond_inheritance.sol -3.09367 0 0
smoke/constructor.sol -3.65267 0 0
events/event_indexed_string.sol -2.36025 0 0
events/event_dynamic_nested_array_storage_v2.sol -1.11354 0 0
events/event_dynamic_array_storage_v2.sol -0.965611 0 0
events/event_emit_from_other_contract.sol -0.724017 0 0
events/event_dynamic_array_storage.sol -0.965611 0 0
functionCall/failed_create.sol -5.70945 0 0
functionCall/creation_function_call_with_salt.sol -2.69084 0 0
functionCall/gas_and_value_basic.sol -3.17486 0 0
functionCall/external_call_to_nonexisting_debugstrings.sol -2.43625 0 0
functionCall/external_call_to_nonexisting.sol -8.02858 0 0
functionCall/mapping_array_internal_argument.sol -0.173324 0 0
functionCall/creation_function_call_with_args.sol -2.69303 0 0
functionCall/send_zero_ether.sol -2.72404 0 0
functionCall/gas_and_value_brace_syntax.sol -3.17486 0 0
externalContracts/ramanujan_pi.sol -3.43954 0 0
externalContracts/prbmath_unsigned.sol -1.26607 0 0
externalContracts/deposit_contract.sol -2.67888 0 0
externalContracts/prbmath_signed.sol -0.0573687 0 0
externalContracts/FixedFeeRegistrar.sol -3.58586 0 0
externalContracts/strings.sol -8.95921 0 0
constructor/constructor_static_array_argument.sol -0.208113 0 0
constructor/arrays_in_constructors.sol -0.974948 0 0
constructor/no_callvalue_check.sol -0.00243829 0 0
constructor/constructor_arguments_external.sol 0.178213 0 0
constructor/bytes_in_constructors_packer.sol -2.87035 0 0
constructor/bytes_in_constructors_unpacker.sol -4.89873 0 0
calldata/copy_from_calldata_removes_bytes_data.sol -0.00837731 0 0
abiencodedecode/abi_decode_simple_storage.sol -0.0956459 0 0
inheritance/value_for_constructor.sol -1.69169 0 0
inheritance/inherited_function_calldata_memory_interface.sol -2.06227 0 0
storage/packed_storage_structs_bytes.sol -1.50832 0 0
abiEncoderV2/abi_encode_calldata_slice.sol 0.120142 0 0
abiEncoderV2/storage_array_encoding.sol -0.0364603 0 0
abiEncoderV2/abi_encode_v2_in_function_inherited_in_v1_contract.sol 1.38454 0 0
abiEncoderV2/calldata_array.sol -25.4391 0 0
abiEncoderV2/abi_encode_v2.sol -0.295678 0 0
userDefinedValueType/erc20.sol -8.14631 0 0
userDefinedValueType/calldata.sol -0.149494 0 0
libraries/using_library_mappings_return.sol -0.139453 0 0
libraries/internal_types_in_library.sol -3.00202 0 0
libraries/using_library_mappings_public.sol 0.152809 0 0
abiEncoderV1/abi_encode_calldata_slice.sol 0.120142 0 0
abiEncoderV1/abi_decode_v2_storage.sol -0.0727945 0 0
abiEncoderV1/struct/struct_storage_ptr.sol -0.652464 0 0
viaYul/array_storage_length_access.sol -0.000246334 0 0
viaYul/array_storage_index_boundary_test.sol -0.913714 0 0
viaYul/array_memory_index_access.sol -0.198685 0 0
viaYul/array_storage_index_access.sol -1.87115 0 0
viaYul/array_storage_push_empty_length_address.sol -0.000308725 0 0
viaYul/array_storage_push_empty.sol -10.2648 0 0
viaYul/copy_struct_invalid_ir_bug.sol -0.0742732 0 0
viaYul/array_storage_index_zeroed_test.sol -2.12432 0 0
salted_create/salted_create_with_value.sol -0.023133 0 0
state/blockhash_basic.sol -3.5543 0 0
array/constant_var_as_array_length.sol -0.282734 0 0
array/function_array_cross_calls.sol -1.38798 0 0
array/reusing_memory.sol -0.179653 0 0
array/byte_array_transitional_2.sol -0.473622 0 0
array/fixed_arrays_in_constructors.sol -0.177818 0 0
array/bytes_length_member.sol -0.0335027 0 0
array/dynamic_multi_array_cleanup.sol -5.26303 0 0
array/dynamic_array_cleanup.sol -0.0186579 0 0
array/fixed_arrays_as_return_type.sol -5.42211 0 0
array/dynamic_arrays_in_storage.sol -6.67631 0 0
array/arrays_complex_from_and_to_storage.sol -0.0653075 0 0
array/fixed_array_cleanup.sol -0.00214802 0 0
array/create_memory_array.sol -4.07982 0 0
array/delete/bytes_delete_element.sol -7.94842 0 0
array/push/nested_bytes_push.sol -0.233309 0 0
array/push/array_push_struct_from_calldata.sol -0.293371 0 0
array/push/array_push_nested_from_calldata.sol -1.03384 0 0
array/push/byte_array_push_transition.sol -1.67488 0 0
array/push/push_no_args_2d.sol -0.0262091 0 0
array/push/array_push_struct.sol -0.26663 0 0
array/push/push_no_args_bytes.sol -1.19988 0 0
array/push/array_push.sol -0.417726 0 0
array/copying/array_copy_storage_storage_different_base_nested.sol -0.397417 0 0
array/copying/array_copy_storage_to_memory_nested.sol -0.65892 0 0
array/copying/array_copy_storage_storage_static_static.sol -0.0012707 0 0
array/copying/array_copy_different_packing.sol -1.50914 0 0
array/copying/array_copy_storage_storage_static_dynamic.sol -0.00811939 0 0
array/copying/array_copy_storage_storage_dynamic_dynamic.sol -0.261058 0 0
array/copying/array_copy_target_simple_2.sol -0.28325 0 0
array/copying/array_nested_calldata_to_storage.sol -0.419844 0 0
array/copying/memory_dyn_2d_bytes_to_storage.sol -6.08932 0 0
array/copying/array_storage_multi_items_per_slot.sol -0.275892 0 0
array/copying/array_nested_memory_to_storage.sol -0.561084 0 0
array/copying/array_copy_including_array.sol -0.0351168 0 0
array/copying/array_copy_target_simple.sol -0.387079 0 0
array/copying/copy_function_internal_storage_array.sol -0.311187 0 0
array/copying/array_of_function_external_storage_to_storage_dynamic.sol -0.0401265 0 0
array/copying/copy_byte_array_in_struct_to_storage.sol -0.037608 0 0
array/copying/array_of_function_external_storage_to_storage_dynamic_different_mutability.sol -0.0402522 0 0
array/copying/array_copy_target_leftover.sol -3.32283 0 0
array/copying/calldata_array_dynamic_to_storage.sol -0.11065 0 0
array/copying/array_copy_storage_storage_struct.sol -0.0762061 0 0
array/copying/bytes_inside_mappings.sol -0.0218622 0 0
array/copying/array_of_struct_memory_to_storage.sol -0.608482 0 0
array/copying/copy_byte_array_to_storage.sol -1.01944 0 0
array/copying/array_copy_calldata_storage.sol 0.0238224 0 0
array/copying/copy_removes_bytes_data.sol -0.00169119 0 0
array/copying/array_copy_nested_array.sol -0.199651 0 0
array/copying/array_of_struct_calldata_to_storage.sol -0.453539 0 0
array/copying/copying_bytes_multiassign.sol -0.0901274 0 0
array/copying/storage_memory_nested.sol -0.917776 0 0
array/copying/storage_memory_packed_dyn.sol -3.07921 0 0
array/copying/array_of_structs_containing_arrays_memory_to_storage.sol -0.585874 0 0
array/copying/array_copy_storage_storage_dyn_dyn.sol -0.0251333 0 0
array/copying/storage_memory_nested_bytes.sol 0.0478209 0 0
array/copying/storage_memory_nested_struct.sol -0.305636 0 0
array/copying/array_copy_storage_storage_different_base.sol -0.400078 0 0
array/copying/array_copy_clear_storage.sol -0.480392 0 0
array/copying/array_of_structs_containing_arrays_calldata_to_storage.sol -2.2852 0 0
array/copying/storage_memory_nested_from_pointer.sol -0.917776 0 0
array/copying/bytes_storage_to_storage.sol -12.566 0 0
array/copying/array_copy_cleanup_uint40.sol -4.14068 0 0
array/pop/array_pop_uint24_transition.sol -0.6207 0 0
array/pop/byte_array_pop_masking_long.sol -0.27375 0 0
array/pop/array_pop_uint16_transition.sol -0.955743 0 0
array/pop/byte_array_pop_copy_long.sol 0.415514 0 0
array/pop/byte_array_pop_long_storage_empty_garbage_ref.sol -0.0539821 0 0
array/pop/byte_array_pop_long_storage_empty.sol -7.6756 0 0
array/pop/array_pop_array_transition.sol -0.192385 0 0
immutable/use_scratch.sol -3.26079 0 0
immutable/multi_creation.sol -0.0219949 0 0
structs/struct_copy_via_local.sol -0.418383 0 0
structs/struct_delete_storage_nested_small.sol -0.252123 0 0
structs/struct_delete_storage_with_array.sol -0.381504 0 0
structs/structs.sol 0.0141335 0 0
structs/memory_structs_nested_load.sol -0.972791 0 0
structs/struct_copy.sol -0.00699766 0 0
structs/struct_delete_storage_with_arrays_small.sol -0.248445 0 0
structs/copy_struct_array_from_storage.sol -1.35973 0 0
structs/struct_containing_bytes_copy_and_delete.sol -0.0934733 0 0
structs/struct_memory_to_storage_function_ptr.sol -0.400123 0 0
structs/conversion/recursive_storage_memory.sol -0.710806 0 0
structs/calldata/calldata_struct_with_nested_array_to_storage.sol -0.529728 0 0
various/erc20.sol -7.51651 0 0
various/senders_balance.sol -3.0777 0 0
various/destructuring_assignment.sol -1.06028 0 0
various/value_complex.sol -5.48924 0 0
various/address_code.sol -9.33142 0 0
various/value_insane.sol -6.0074 0 0
various/swap_in_storage_overwrite.sol -0.0173179 0 0
various/skip_dynamic_types_for_structs.sol -0.0838823 0 0
isoltestTesting/balance_other_contract.sol -6.03229 0 0

@ekpyron ekpyron force-pushed the removeInliningConstraint branch from 8b11252 to 8fef645 Compare March 2, 2022 16:02
@ekpyron ekpyron changed the base branch from develop to assemblyAnnotationDialectString March 2, 2022 16:02
@ekpyron ekpyron force-pushed the assemblyAnnotationDialectString branch from caf191b to 46d8611 Compare March 2, 2022 16:07
@ekpyron ekpyron force-pushed the removeInliningConstraint branch from 8fef645 to 7f1f87a Compare March 2, 2022 16:10
@@ -89,6 +89,8 @@ function elementfi_test
# TODO: Remove when https://github.com/element-fi/elf-contracts/issues/243 is fixed.
sed -i 's|^\s*require(_expiration - block\.timestamp < _unitSeconds);\s*$||g' contracts/ConvergentCurvePool.sol

find . -name "*.sol" -exec sed -i -e 's/^\(\s*\)\(assembly\)/\1\/\/\/ @solidity memory-safe-assembly\n\1\2/' '{}' \;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one actually isn't memory-safe... and apparently I was fooled by our test cases in that just inlining unconditionally will just work and not break anything :-(.

@ekpyron ekpyron force-pushed the removeInliningConstraint branch from 7f1f87a to 2775355 Compare March 2, 2022 16:35
@ekpyron
Copy link
Member Author

ekpyron commented Mar 2, 2022

For the working external tests I get:

--- summarized-benchmarks.json  2022-03-02 18:02:11.482076212 +0100
+++ summarized-benchmarks-more-inlining.json   2022-03-02 18:00:44.111559280 +0100
     "bleeps": {
         "ir-optimize-evm+yul": {
-            "bytecode_size": 132839,
+            "bytecode_size": 129306,
             "deployment_gas": 0,
-            "method_gas": 39289198,
+            "method_gas": 39158584,
             "version": "bb90cd0"
         },
...
    "gnosis": {
         "ir-optimize-evm+yul": {
-            "bytecode_size": 56037,
+            "bytecode_size": 53436,
             "deployment_gas": null,
             "method_gas": null,
...
     "gnosis2": {
         "ir-optimize-evm+yul": {
-            "bytecode_size": 46641,
+            "bytecode_size": 44358,
             "deployment_gas": null,
             "method_gas": null,
...
     "prb-math": {
         "ir-optimize-evm+yul": {
-            "bytecode_size": 38354,
+            "bytecode_size": 37545,
             "deployment_gas": null,
             "method_gas": null,
...
     "yield_liquidator": {
         "ir-optimize-evm+yul": {
-            "bytecode_size": 89120,
-            "deployment_gas": 15449067,
-            "method_gas": 2947797,
+            "bytecode_size": 85129,
+            "deployment_gas": 14831189,
+            "method_gas": 2938537,
             "version": "74f969a"
...
     "zeppelin": {
         "ir-optimize-evm+yul": {
-            "bytecode_size": 546357,
+            "bytecode_size": 520326,
             "deployment_gas": null,
             "method_gas": null,

Unfortunately we don't get runtime gas stats for some yet... but interestingly code size also seems to generally decrease...

But it still sucks a bit that it does still bring back more stack-too-deep cases.

@chriseth
Copy link
Contributor

chriseth commented Mar 2, 2022

Impressive!

Base automatically changed from assemblyAnnotationDialectString to develop March 7, 2022 12:03
@ekpyron ekpyron force-pushed the removeInliningConstraint branch 2 times, most recently from 409ea3c to 2d52471 Compare March 16, 2022 17:10
// Do not inline into already big functions.
if (m_functionSizes.at(_callSite) > 45)
if (m_functionSizes.at(_callSite) > (usesNewCodeTransform ? 450 : 45))
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So this version seems to fix all stack-too-deep errors in the external tests.
But I also have a hunch that #12132 might actually help a lot with stack pressure as well, so maybe on top of that we can even drop any boundary...

@cameel
Copy link
Member

cameel commented Mar 28, 2022

All the external failures here at this point seem to be due to NomicFoundation/hardhat#2453. I think it would be fine to just disable these tests until the issue is fixed.

@leonardoalt
Copy link
Member

@ekpyron maybe fix the conflicts here so you can rebase and test the external contracts again?

@@ -196,7 +205,7 @@ bool FullInliner::shallInline(FunctionCall const& _funCall, YulString _callSite)
break;
}

return (size < 6 || (constantArg && size < 12));
return (size < (usesNewCodeTransform ? 8 : 6) || (constantArg && size < (usesNewCodeTransform ? 16 : 12)));
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@cameel Actually: tweaking this is also something to do here.

@cameel
Copy link
Member

cameel commented Apr 13, 2022

Just for reference, today's discussion with @ekpyron about what is still to be done here. The most important part:

@ekpyron

But generally, disabling tests that fail due to heuristics is really the main thing to do for now I guess...
Or actually: tweaking https://github.com/ethereum/solidity/pull/12731/files#r849338706 also.
But we don't necessarily need to do that in one step.
But that's something where #12132 might help. The thing is that some of our panic helpers don't fall under the current return (size < 6 || (constantArg && size < 12)); threshold. And due to that, the current code transform won't notice that those paths revert and will keep merging stack layouts, etc... while with #12132 we may get away with just not touching https://github.com/ethereum/solidity/pull/12731/files#r849338706 at all in a first step and only tweaking it in a second step...

@cameel

You were doing this tweaking based on gas improvements and whether ext tests fail or did you also have other criteria?

@ekpyron

Yes - resp. we were wondering somewhere else why optimized IR code still had panic_*() function calls, since we'd have expected them to be inlined - so I wanted to see which values would be needed to inline those - not sure if the values currently in the PR do it or not.
The ideal version of the PR would just remove https://github.com/ethereum/solidity/pull/12731/files#r828298176 entirely without any new threshold. (And without changing https://github.com/ethereum/solidity/pull/12731/files#r849338706 at first, even though that would be the next step)
I think the only external test that was failing due to that was elementfi...
I actually also wanted to have a look at that - that looked like it emitted a memoryguard, so it allowed stack-to-memory, but still ran into a stack-too-deep error, which at this point I'd consider a bug case.

Failing compilation with a stack-too-deep error.
(due to the heightened stack pressure due to more inlining - where the hope was that this wouldn't happen anymore these days ;-))

@ekpyron ekpyron changed the base branch from develop to disable-ext-test-cases-broken-after-relaxing-inlining May 11, 2022 18:06
@ekpyron ekpyron force-pushed the removeInliningConstraint branch from a6d231e to 65695e3 Compare May 11, 2022 18:33
@ekpyron ekpyron force-pushed the removeInliningConstraint branch 2 times, most recently from ff71e3d to c592dcb Compare May 11, 2022 19:50
@ekpyron ekpyron force-pushed the disable-ext-test-cases-broken-after-relaxing-inlining branch from ed44ef0 to 826fc47 Compare May 20, 2022 10:42
@ekpyron ekpyron force-pushed the removeInliningConstraint branch from c592dcb to a59c0ce Compare May 20, 2022 10:48
@cameel cameel force-pushed the disable-ext-test-cases-broken-after-relaxing-inlining branch from 826fc47 to cc66991 Compare May 20, 2022 18:54
@cameel cameel force-pushed the removeInliningConstraint branch from a59c0ce to 7b7409a Compare May 20, 2022 18:54
@cameel cameel force-pushed the disable-ext-test-cases-broken-after-relaxing-inlining branch from cc66991 to 52e796c Compare May 20, 2022 18:58
@cameel cameel force-pushed the removeInliningConstraint branch from 7b7409a to 2817678 Compare May 20, 2022 18:58
@cameel
Copy link
Member

cameel commented May 20, 2022

#12937 updated. Now all external tests should be passing here.

@chriseth chriseth force-pushed the disable-ext-test-cases-broken-after-relaxing-inlining branch from 52e796c to 46eff4b Compare May 23, 2022 10:30
@chriseth chriseth force-pushed the removeInliningConstraint branch 2 times, most recently from 57e12cb to 0fb13eb Compare May 23, 2022 11:35
@chriseth chriseth force-pushed the disable-ext-test-cases-broken-after-relaxing-inlining branch from 46eff4b to 49d5c0a Compare May 23, 2022 11:37
@chriseth chriseth force-pushed the removeInliningConstraint branch from 0fb13eb to 77038aa Compare May 23, 2022 11:37
@cameel
Copy link
Member

cameel commented May 23, 2022

Updated benchmarks from 1070566.

ir-optimize-evm+yul

Relative

project bytecode_size deployment_gas method_gas
bleeps -3.25% ✅ 0% -0%
brink -7.5% ✅
colony 0%
elementfi -2.45% ✅
ens 0% -6.37% ✅ -0.64% ✅
euler -2.52% ✅ -1.68% ✅ -2.07% ✅
gnosis -3.83% ✅ -4.33% ✅ -0.02% ✅
perpetual-pools -4.56% ✅ -2.66% ✅ -0.99% ✅
pool-together -7.06% ✅ -5.58% ✅ -0.37% ✅
prb-math -3.53% ✅ -3.48% ✅ 0%
trident -9.78% ✅ -7.95% ✅ -6.25% ✅
uniswap -4.28% ✅ -4.5% ✅ -1.24% ✅
yield_liquidator -7.12% ✅ -6.1% ✅ -0.5% ✅
zeppelin -4.75% ✅ -3.21% ✅ -0.18% ✅

Absolute

project bytecode_size deployment_gas method_gas
bleeps -4261 0 -113
brink -1018
colony 0
elementfi -14314
ens 0 -1984437 -763921
euler -4604 -601676 -62018944
gnosis -2593 -169903 -11399
perpetual-pools -9474 -1107332 -8007246
pool-together -15248 -2061198 -234934
prb-math -1341 -285835 0
trident -31030 -2178611 -27085001
uniswap -7385 -905462 -33994790
yield_liquidator -6306 -931624 -14831
zeppelin -27540 -3400500 -770162

@@ -113,7 +113,7 @@ contract ERC20 {
// ----
// constructor()
// ~ emit Transfer(address,address,uint256): #0x00, #0x1212121212121212121212121212120000000012, 0x14
// gas irOptimized: 418388
// gas irOptimized: 364503
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wow, looks like UDVTs are getting a nice boost.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice, as it should be!

Base automatically changed from disable-ext-test-cases-broken-after-relaxing-inlining to develop May 23, 2022 13:17
@chriseth chriseth dismissed a stale review via 77038aa May 23, 2022 13:17
@chriseth chriseth marked this pull request as ready for review May 23, 2022 13:17
@chriseth
Copy link
Contributor

It's great that the bytecode size also improves for all external tests!

@chriseth chriseth merged commit 45030f0 into develop May 23, 2022
@chriseth chriseth deleted the removeInliningConstraint branch May 23, 2022 13:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
has dependencies The PR depends on other PRs that must be merged first optimizer
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants