-
Notifications
You must be signed in to change notification settings - Fork 199
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
feat(mem2reg): Remove trivial stores #5865
Conversation
Changes to Brillig bytecode sizes
🧾 Summary (10% most significant diffs)
Full diff report 👇
|
Changes to circuit sizes
🧾 Summary (10% most significant diffs)
Full diff report 👇
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some potential aliasing issues
I'm kind of surprised by the brillig_cow_assign failure looking at the SSA:
When comparing to the SSA without this optimization the only difference is there is an additional Edit: Found this hack (
|
Accounting the extra re-load and re-store for inc_rc instructions fixes the Interestingly,
Then with those passes we get the following:
We still get a reduction without these extra mem2reg and DIE passes, but we should try to remove these instructions as we know we can. We just have to figure out why it is causing issues for uhashmap. We could merge these changes as they still provide a nice reduction in poseidon2, hashmap, and uhashmap. Then in a follow-up we can address getting rid of these leftover stores. |
Ideally we get rid of those extra passes anyway. It's a fairly unsatisfactory tradeoff with compilation time IMO to add two extra passes to get rid of a couple extra instructions in some brillig functions. More concerning is why running these again (although the culprit is presumably mem2reg) produces an issue in the first place. |
Yeah agreed. I'm going to mark this PR ready for review without those extra passes this PR still shows a good improvement.
Then in a follow-up we can investigate the cause of |
…to mv/simplify-immediate-stores
Instruction::Store { address, value, from_rc } => { | ||
writeln!(f, "store {} at {}, from_rc {}", show(*value), show(*address), *from_rc) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not a big fan of including from_rc
on every store instruction for a mem2reg-specific issue.
Can we add tracking to mem2reg specifically instead? E.g. if we see a load -> dec-rc -> store we mark that we can't remove the store?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll look at switching to that
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I switched to tracking the current rc reload per instruction with an Option<(ValueId, bool)>
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah something looks to be failing. I had it passing before but I guess I made a bad change while cleaning up.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had moved when I was calling my method to track the rc reload state, but this led to inadvertently calling the method on the wrong instruction id. This is now fixed and the PR is ready for review again.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks to still be failing on the debugger actually as the debugger inserts foreign calls which are breaking up the expected block of this form:
v72 = load v57
inc_rc v72
v73 = load v57
inc_rc v73
store v73 at v57
store v72 at v60
In the debugger we see the following before mem2reg after the inlining pass:
v76 = load v14
inc_rc v76
v77 = load v14
inc_rc v77
store v77 at v14
call v80(Field 1, v76)
inc_rc v76
v81 = load v14
inc_rc v81
store v81 at v14
store v76 at v26
@vezenovm if it helps for this PR I was talking with @sirasistant who mentioned changing the design of how inc/dec-rc works in brillig. A side-effect of that work would be that we no longer would have to |
Yeah it should. The main issue here is I have to differentiate which stores I can actually remove if the known value of a store equals the address it is storing into. Without inc_rc/dec_rc, I can safely remove any of these stores. It does look to work with the solution on this branch. Although it is a bit hacked around as I have |
We can pause this work for a week or so then while the brillig changes are being worked on. Hopefully with the removal of the special tracking uhashmap won't fail anymore. |
I haven't nailed down the exact cause but I think |
Ok I have nailed down the cause of the failure and it is in fact unrelated to inc_rc/dec_rc. When cleaing up stores we check a couple things:
Now that I am cleaning up loads as well (#5905) we can remove some stores if we know all loads to that store have been removed. However, I was not checking whether the address of the store we want to remove is possibly used as a reference directly such as in the parameter of a call. |
@jfecher I was thinking we could replace this PR with (#5935) which handles inc_rc / dec_rc in the safest manner by just always assuming when we have an inc_rc/dec_rc before a store we cannot remove that store. In this PR I was attempting to check for specifically this case but that was leading to issues. PR #5935 just accepts a smaller improvement (21% on this PR -> 7% on the new one) for safety. And then when inc_rc/dec_rc are redesigned we can remove the small check. |
Changing to draft for clarity. |
Closing in favor of #5935 |
… mem2reg (#5935) # Description ## Problem\* Partially resolves #4535 Replaces #5865 ## Summary\* When we see a load we mark the address of that load as being a known value of the load result. When we reach a store instuction, if that store value has a known value which is equal to the address of the store we can remove that store. We also check whether the last instruction was an `inc_rc` or a `dec_rc`. If it was we do not remove the store. ## Additional Context ## Documentation\* Check one: - [X] No documentation needed. - [ ] Documentation included in this PR. - [ ] **[For Experimental Features]** Documentation to be submitted in a separate PR. # PR Checklist\* - [X] I have tested the changes locally. - [X] I have formatted the changes with [Prettier](https://prettier.io/) and/or `cargo fmt` on default settings.
Description
Problem*
Partially resolves #4535. We can still do some more cleanup but will handle that in a follow-up. References the PR discussion comments for more context.
Summary*
Just marking the result of a load known was causing some failures, specifically for arrays. So for now I just look for trivial stores that are immediately storing the same value that was just loaded.
Also testing on CI as I keep getting rayon errors with cargo test for some reason. Making this check mark more values known was also difficult to due to this issue with testing so I am just pushing the more trivial case in this draft.
Additional Context
Documentation*
Check one:
PR Checklist*
cargo fmt
on default settings.