Conversation
c987b2b to
38fd9ac
Compare
16b2cc9 to
30c820c
Compare
|
There was an error when running Please check that your changes are working as intended. |
libyul/optimiser/SSAValueTracker.cpp
Outdated
|
|
||
| #include <libyul/optimiser/SSAValueTracker.h> | ||
|
|
||
| #include "liblangutil/Exceptions.h" |
30c820c to
2a78055
Compare
|
There was an error when running Please check that your changes are working as intended. |
libyul/optimiser/SSAValueTracker.cpp
Outdated
|
|
||
| #include <libyul/optimiser/SSAValueTracker.h> | ||
|
|
||
| #include "liblangutil/Exceptions.h" |
cba7f5b to
31b25f9
Compare
There was a problem hiding this comment.
Pull request overview
This PR updates the Yul optimizer’s UnusedStoreEliminator pipeline to avoid incorrect mstore removals when the input is not in pseudo-SSA form (notably when function parameters are involved), and adds targeted optimizer tests for the “no SSA transform” scenario described in #16458.
Changes:
- Extend
SSAValueTrackerto treat unassigned function parameters as valid SSA roots when checking SSA-ness transitively through dependencies. - Filter the knowledge-base SSA input used by
UnusedStoreEliminatorto only include expressions that are in SSA form together with their dependencies. - Add a dedicated
unusedStoreEliminatorNoSsaTransformtest step and new Yul tests that exercise the problematic cases.
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
libyul/optimiser/SSAValueTracker.h |
Adds an SSA-with-dependencies query API and tracks function parameters. |
libyul/optimiser/SSAValueTracker.cpp |
Implements dependency-based SSA checking and parameter tracking during AST walk. |
libyul/optimiser/UnusedStoreEliminator.cpp |
Builds the SSA value map using only SSA-safe expressions (with SSA-safe dependencies). |
test/libyul/YulOptimizerTestCommon.cpp |
Adds a new optimizer test step that runs UnusedStoreEliminator without SSATransform. |
test/libyul/yulOptimizerTests/unusedStoreEliminatorNoSsaTransform/mstore_location_reassigned.yul |
New regression test covering non-SSA reassignment affecting mstore location. |
test/libyul/yulOptimizerTests/unusedStoreEliminatorNoSsaTransform/function_parameter_as_mstore_location_unrelated.yul |
New test where parameter-derived store location should be removable (non-overlapping). |
test/libyul/yulOptimizerTests/unusedStoreEliminatorNoSsaTransform/function_parameter_as_mstore_location_covering.yul |
New test where parameter-derived store location must be kept (overlapping return). |
test/libyul/yulOptimizerTests/unusedStoreEliminatorNoSsaTransform/function_parameter_reassinged_as_mstore_location_unrelated.yul |
New test intended to cover reassigned-parameter non-overlap scenario. |
test/libyul/yulOptimizerTests/unusedStoreEliminatorNoSsaTransform/function_parameter_reassinged_as_mstore_location_covering.yul |
New test covering reassigned-parameter overlapping scenario. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
...StoreEliminatorNoSsaTransform/function_parameter_reassigned_as_mstore_location_unrelated.yul
Show resolved
Hide resolved
9cf23ac to
7d014ec
Compare
| else | ||
| { | ||
| solAssert(std::holds_alternative<Literal>(*_expression), "Impossible expression type"); | ||
| return true; | ||
| } |
There was a problem hiding this comment.
| else | |
| { | |
| solAssert(std::holds_alternative<Literal>(*_expression), "Impossible expression type"); | |
| return true; | |
| } | |
| solAssert(std::holds_alternative<Literal>(*_expression), "Impossible expression type"); | |
| return true; |
| // let a := add(arg, 1) | ||
| // let b := arg | ||
| // let outLen := 32 | ||
| // mstore(a, 0xAA) |
There was a problem hiding this comment.
This worked before the fix as well, since you're not reassigning arg?
There was a problem hiding this comment.
Yes, but I added function parameters set to the SSAValueTracker, because I need to know them if they are not reassigned and if not they properly close the closed set. This is just a simple test of this.
...nusedStoreEliminatorNoSsaTransform/transitive_dependency_reassigned_prevents_elimination.yul
Outdated
Show resolved
Hide resolved
...ibyul/yulOptimizerTests/unusedStoreEliminatorNoSsaTransform/multi_return_var_not_tracked.yul
Outdated
Show resolved
Hide resolved
3ef065c to
df081a5
Compare
|
There was an error when running Please check that your changes are working as intended. |
bbdfc8c to
b871cd5
Compare
There was a problem hiding this comment.
Please remember that this will need a buglist entry.
Without it the PR is not really finished so it should still be a draft.
There was a problem hiding this comment.
bug list updated. How about the blogpost link? I changed it to draft for now.
There was a problem hiding this comment.
You can leave it unfilled until we know when we're releasing this. URLs are predictable, based on date and title (which should match the bug ID) so we could create one already, but if we do it now, we can easily forget to update the date and we'll end up with a broken link. So for now I'd put in something that clearly looks like a placeholder.
There was a problem hiding this comment.
I used X/Y/Z placeholder for now as it was done in prev cases.
b871cd5 to
8f69008
Compare
87e9ec9 to
ceee60a
Compare
58a2f46 to
ccc99a9
Compare
libyul/optimiser/SSAValueTracker.h
Outdated
There was a problem hiding this comment.
Since this is never iterated over in a way where the order would matter (I think, double check this), we could also look at unordered_map or boost::flat_map.
There was a problem hiding this comment.
Changed. It's used in 2 different places (FullInliner and the USE) and it looks they do don't depend on the order of the values in the map.
6352590 to
1b21aa9
Compare
clonker
left a comment
There was a problem hiding this comment.
Two typos in your filenames. Also I think the unusedStoreEliminatorNoSsaTransform tests do a bit much work. I get that you took that from unusedStoreEliminator tests but it in no way reflects the documented prerequisites. Also not in the already existing tests.
Beyond that I think it would be good to add a reproducer regression test with simply S: as optimizer steps.
...dStoreEliminatorNoSsaTransform/function_parameter_reassigned_as_mstore_location_covering.yul
Show resolved
Hide resolved
...StoreEliminatorNoSsaTransform/function_parameter_reassigned_as_mstore_location_unrelated.yul
Show resolved
Hide resolved
e63d28b to
7db0929
Compare
clonker
left a comment
There was a problem hiding this comment.
The introduced field should be fixed (also in bugs_by_version.json), beyond that one tiny cosmetic thing that would help improve (my) understanding of a comment in the code, otherwise LGTM!
docs/bugs.json
Outdated
| "summary": "When the UnusedStoreEliminators optimizer step is run on non-SSA AST form, it may result in incorrect removal of storage or memory writes.", | ||
| "description": "Solidity allows defining custom user-defined optimizer sequences. In version 0.8.12, the unused store eliminator was introduced to remove redundant writes to storage or memory. The bug was in this optimizer step's implementation. It used SSAValueTracker to identify variables that are never assigned. Based on this set of unassigned variables, a knowledge base is created to track current variable values. This knowledge is necessary for deciding whether memory or storage writes can be safely removed. Unfortunately, SSAValueTracker correctly removed assigned variables from the SSA variable set, but failed to remove variables that depend on those assigned variables. This oversight made it possible to construct inline assembly code that was incorrectly optimized by removing necessary writes. As a result, contracts compiled with different optimization sequences could exhibit different runtime behavior. The bug was introduced in version 0.8.12 alongside the unused store eliminator implementation. It was fixed in version 0.8.35 by implementing additional filtering of the variable set returned by SSAValueTracker and extending this set by functions parameters values.", | ||
| "link": "https://blog.soliditylang.org/2026/X/Y/Z/", | ||
| "introduced": "0.8.12", |
There was a problem hiding this comment.
| "introduced": "0.8.12", | |
| "introduced": "0.8.13", |
didn't exist in 0.8.12
| // It should be eliminated, because the location is the same, but if we look at the result, second pass of the | ||
| // optimizer will eliminate properly first `sstore`. |
There was a problem hiding this comment.
I had to read that comment like five times before I understood it :D Perhaps this is better for dummies like me?
| // It should be eliminated, because the location is the same, but if we look at the result, second pass of the | |
| // optimizer will eliminate properly first `sstore`. | |
| // the first sstore could theoretically be eliminated since loc == arg, | |
| // but USE cannot prove this without a known constant value for arg; | |
| // a subsequent optimizer pass (after, e.g., CSE resolves the alias) would eliminate it |
purely cosmetic of course, it's also fine as-is.
Co-authored-by: Nikola Matić <nikola.matic@ethereum.org>
7db0929 to
0ac2520
Compare
| "link": "https://blog.soliditylang.org/2026/X/Y/Z/", | ||
| "introduced": "0.8.13", | ||
| "fixed": "0.8.35", | ||
| "severity": "low" |
There was a problem hiding this comment.
Just a note that one of the blockers for this is having a release date and severity agreed on by the team.
I don't think this one can get into the next release if we're going to have one soon. We need to deal with #16508 first.
SSAValueTrackerimplementation has changed to support also variables which are functions parameters. Previous implementation omitted function parameters because they do not have default value.SSAValueTrackersupported only variables which are initialised, directly in the code or by default value. Functions return variables are set to0, but function parameters have values passed by the caller. Additional set is added to store function parameters which are not assigned in the function body. This change allowed to implement function which filters out variables which (with their dependencies) are not in SSA form. It's needed to properly define a set which serves as an input to the knowledge base.
Fixes: #16458