Comments (8)
I think I have the same issue.
Sol code: https://gist.github.com/leonardoalt/382603dec4da0425d073ffeed9356e7c
The code above compiled with 0.8.25 and --via-ir
leads to ~13k code size. With --optimizer
that number goes to ~31k (above contract size limit).
I talked to @nikola-matic and we tried a few different things. I tried the optimizer sequence "dhfoDgvulfnTUtnIf[xa[r]EscLMcCTUtTOntnfDIulLculVcul [j]Tpeulxa[rul]xa[r]cLgvifCTUca[r]LSsTOtfDnca[r]Iulc]jmul[jul] VcTOcul jmul:fDnTOcmu"
(without F
) and it didn't help.
Here's a smaller contract where a similar thing happens (~4k to ~6k code size without/with optimizer):
https://gist.github.com/leonardoalt/74fa6d3a05c9282638514c7e29760df9, though I think the first one I posted is more relevant.
from solidity.
That's something that's not supposed to be happening. Looking at the current inlining heuristics, the only situation when we'd inline a huge function is when it's used once.
The only thing that could explain this that comes to mind is the FunctionSpecializer step (F
), which may create a copy of the function if you call it with a literal. This could lead to multiple copies of the function that are then being inlined by FullInliner (i
). The inliner runs before the specializer but that part of the sequence is repeated multiple times so those specialized functions can still get inlined on the next pass.
You could try to verify this by using a custom sequence with F
removed. And if that's the case, a temporary workaround would be to call these functions with something that's not a literal to bypass the step. Putting it in a variable might do the trick, but you might also need something more complicated since the optimizer can still to a large extent deduce that something evaluates to a literal.
As for the long-term solution, maybe we should reconsider whether specializer is worth it if it can run into such corner cases. Or put some limits on it. I'm actually working on improving the default sequence right now and I can check check what the effect of removing the specializer is in practice, but would be best if you could confirm this first.
Do you have a repro for this? If it's of a reasonable size, I could even include it as another test contract in my benchmark.
from solidity.
Thank you for the hint, I will give this is try and report back.
from solidity.
PS: regarding Repro, unfortunately no and I can't share this specific contract. I'll see if your suggestions makes a difference and will then see if I can quickly whip up something.
from solidity.
Ok I used the default options from OptimiserSettings.h and removed F, and indeed that massively reduced my contract size. I also tried adding an intermediate function to remove constant parameters for the large function, but as you suspected, the optimizer realized that and it had no effect.
I'll play around a bit and see if I can find something else worthwhile reporting.
Thanks again for your help!
from solidity.
I think I managed to create a reproducer. It has one big lnonsense function, and two external entry points, calling the function with constant arguments. It gets specialized for both callers, unless I remove "F" from the optimizer options.
While probably not minimal, I hope that helps as a starting point.
from solidity.
I experimented with the specializer in the new sequence a bit and unfortunately this is tricky. There's a complex interaction between the specializer and the inliner and how good the result is often depends on which one is first to get code transformed enough to act on it.
For example here's an example of a 10% increase in runtime gas cost when the specializer does not eliminate a literal argument from a function called in a tight loop. The tricky bit is that the best version is one where calls to the function outside of the loop are inlined and the ones in the loop are only specialized. The current sequence somehow strikes that balance, my new one does not.
I managed to address that by adjusting the new sequence, which lowered gas use in this example but then bytecode size in another example increased by 8%. This time because the specializer duplicated a function containing large constants. The interesting thing is that originally the new sequence was beating the current one by a large margin on this example because it was not duplicating the function at all (current sequence duplicates it once). With the adjustment it started duplicating it twice.
I also tried removing F
from the current sequence and it does not usually improve results. Specialization seems important, just has to be used at the right time.
Overall my impression is that this is something that will be hard to address by just rearranging the sequence. We gain in some examples, lose in others. We do need some heuristics inside the specializer to decide when it's worth it.
from solidity.
I'm not sure how practical that would be, but just an idea. I personally don't care too much about a bit of bloat in the contract and prefer lower execution costs, as long as it stays within deployable limits. So as an idea until a proper heuristic is in place, how about just compiling it with full specialization, then if the size exceeds the limit, avoid specialization for the biggest resulting function, then for the second biggest one etc, until it reaches a valid size or none is left.
from solidity.
Related Issues (20)
- Z3 build error
- Calling solc with `--standard-json` with `"language":"yul"` with tstore in the YUL leads to no generated code HOT 1
- Nested memory arrays not implemented in ABICoder V1
- Switch all MacOS scripts to use GNU utils
- codegen error: Copying of type struct memory[] memory to storage not yet supported. HOT 1
- IR-based Codegen error: too deep inside the stack.
- SMTChecker: Error trying to invoke SMT solver
- SMTChecker: struct variable push() cause false positive HOT 1
- ABICoderv1 and AST import cause storage difference due to function-type variable assignment
- mstore(add(mload(0x80), 0x20), xx) cause IR-based codegen execution revert.
- IR-base codegen, abicoder v1, Ast import lack of memory protection mechanism
- write to uint[2][2] calldata fail in IR-based Codegen HOT 1
- IR-based codegen: Modifying the length of a dynamic array to a large number in assembly, followed by a push() operation, will cause a revert.
- Unnamed return variable is displayed incorrectly in counter example
- When accessing an out-of-bounds index in a fixed-size array, the contract execution reverts
- Unreachable code warning for internal function called by an abstract contract HOT 1
- Compiler error on attempting to use hexadecimal literals of length 39-41 as integers HOT 1
- Unable to check existence of precompiled contract by its address or get its code in VM or Sepolia testnet HOT 1
- Yul interpreter subset for side-effect-free evaluation
- do-while results in redundant branching instructions when compiling via IR HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from solidity.