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

better heuristics for choosing variables to move to memory #14067

Open
sifislag opened this issue Mar 23, 2023 · 2 comments
Open

better heuristics for choosing variables to move to memory #14067

sifislag opened this issue Mar 23, 2023 · 2 comments
Labels
high impact Changes are very prominent and affect users or the project in a major way. medium effort Default level of effort selected for development It's on our short-term development viair
Projects

Comments

@sifislag
Copy link

Description

I've been looking at bytecodes produced using the --via-ir pipeline and I noticed that in most cases, popular constants (0, 4, etc.) are pushed to the stack on the function selector code and shared between public functions. I stumbled upon a contract where the memory mover kicks in to resolve stack too deep errors. This behavior can be seen in the produced yul code, with 0 being stored at memory offset 0xa0. After this point the constant is loaded 271 times (can be observed by searching "60a051" in the deployed bytecode).

So in this case the sequence 60a051 is used instead of 6000, adding 271 extra bytes to the deployed bytecode. Thought to report it as it will probably be common in large programs.

Environment

  • Compiler version: 0.8.17 (also on 0.8.19)
  • Target EVM version (as per compiler settings): london
  • Operating system: ubuntu 20.04

Steps to Reproduce

I got the contract's code concatenated to a single file from here and compiled using 0.8.19 (after removing imports, etc). The same behavior is present. I'm not posting it here because its too large.

@github-actions github-actions bot added this to Triage in Solidity Mar 23, 2023
@ekpyron
Copy link
Member

ekpyron commented Mar 27, 2023

Yeah, there's two underlying issues involved in this - for once the memory-mover currently naively chooses the first candidate for moving to memory to solve stack-too-deep errors rather than analyzing the cost for all candidates and choosing the cheapest one based on some heuristics. Secondly, the code transform (i.e. the transformation from yul code to evm bytecode) does currently not always make use of the fact that it knows the value of constants and can replace variable references by constants.

Both of this are known problems and it's on our agenda to improve both of the components involved.
I'll be linking this issue to #13721, which will involve improving the mentioned code transform to account for the example case you're posting - thank you very much for that, concrete examples help a lot in tweaking these mechanisms!

Beyond that I'll leave this issue open, but will repurpose it to a more general improvment of the heuristics of moving variables to memory, which is the second component involved in this.

@ekpyron ekpyron changed the title Using the memory mover on constants can end up producing larger bytecodes better heuristics for choosing variables to move to memory Mar 27, 2023
@ekpyron ekpyron added medium effort Default level of effort high impact Changes are very prominent and affect users or the project in a major way. must have Something we consider an essential part of Solidity 1.0. viair selected for development It's on our short-term development and removed must have Something we consider an essential part of Solidity 1.0. labels Mar 27, 2023
@ekpyron ekpyron moved this from Triage to Focus Tasks in Solidity Mar 27, 2023
@ekpyron ekpyron moved this from Focus Tasks to Implementation Backlog in Solidity Mar 27, 2023
@sifislag
Copy link
Author

Thanks for the explanation!
I can get you more examples if that'd be helpful. I ran a quick analysis on ~900 contracts compiled using --via-ir, in 42 of them the memory mover was used (according to my heuristic) and I found 20 instances where small (single byte) constants are stored on an offset reserved by the memory mover.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
high impact Changes are very prominent and affect users or the project in a major way. medium effort Default level of effort selected for development It's on our short-term development viair
Projects
No open projects
Solidity
  
Implementation Backlog
Development

No branches or pull requests

2 participants