-
Notifications
You must be signed in to change notification settings - Fork 12.7k
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
Mir-Opt for copying enums with large discrepancies #85158
Conversation
This comment has been minimized.
This comment has been minimized.
28da2d2
to
8d8c374
Compare
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.
Hmm, so the idea is to transform: _a = _b;
into:
_index = discriminant(_b);
_bytes = [size of each variant in bytes][_index]
CopyNonOverlapping(src: &_b as *const u8, dst: &_a as *mut u8, count: _bytes);
The transformation is localized to a single assignment, requires layout information, some aspects of it feel non-trivial to express directly in MIR (e.g., preserving the alignment). Maybe codegen would be a better fit?
8d8c374
to
b65bb73
Compare
This general pattern for copying the data appears to be opaque to memcpy optimizations, i.e., every single transformed copy remains. Any ideas how this could be improved? |
That would mean it would have the monomorphized versions of the enum too, right? Could be handy for anything using a generic |
Mmmm I've not written anything for codegen at all, but if that makes more sense I can close this and move it to that, altho seeing a guide before it would be helpful. |
As you prefer. The current implementation is not that far from the point where we could run some tests on it. The one missing component is a mapping from a discriminant to a variant index (or limiting the transformation to the cases where there is direct correspondence between the two). |
b65bb73
to
6eaa543
Compare
ah I thought reading from the array of sizes was handled around line 132, but I guess mapping discriminants to variant idxes is not guaranteed to be 1-1, is there anyway to check that? |
I believe enum Foo {
Bar = 2,
Baz = 0,
} has variant index 0 for |
The |
Does this fix #54360? |
I believe so? I don't remember the original issue. |
6eaa543
to
d6b74be
Compare
This comment has been minimized.
This comment has been minimized.
d6b74be
to
90f8c1c
Compare
This comment has been minimized.
This comment has been minimized.
90f8c1c
to
ad67765
Compare
Variants::Multiple { variants, .. } => { | ||
let min = variants.iter().map(|v| v.size).min().unwrap(); | ||
let max = variants.iter().map(|v| v.size).max().unwrap(); | ||
if max.bytes() - min.bytes() < D { |
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.
The max - min
criterion is based on the most optimistic scenario.
Consider two enums with the same maximum absolute deviation in variant sizes. The first enum has one large outlier and remaining variants are small, the second enum conversely has one small outlier and remaining variants are large. Both enums would be be equally good candidates under current criterion, but the first one would seem like a much better candidate.
What about assuming that variants are uniformly distributed and calculating expected reduction in the number of bytes copied?
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.
oops I never directly addressed this, I'm not sure if uniform distribution makes a ton of sense, as I'd expect if this is hit that one variant is probably significantly larger than the others. Probably something to experiment with.
In terms of placement in MIR pipeline, I would put it towards the end, somewhere after SimplifyLocals, maybe just last? I wouldn't expect it to create any new optimization opportunities. |
Changing a bunch of struct constructors to `from`, no extra destructuring, getting the type of the discriminant.
Since we're changing a bunch of stuff, necessary to remove some codegen tests which look for specific things. Also attempting to restart a test which timed out, maybe due to fastly failing?
Instead of storing an extra array for discriminant values, create an allocation there and store those in an allocation immediately.
There is a distinction between running this on wasm and i686, even though they should be identical. This technically is not _incorrect_, it's just an unexpected difference, which is worth investigating, but not for correctness.
c67e312
to
e5352d9
Compare
e5352d9
to
15d4728
Compare
Should be ok to retry submitting again at this point |
@bors r+ |
☀️ Test successful - checks-actions |
Finished benchmarking commit (5a8dfd9): comparison URL. Overall result: no relevant changes - no action needed@rustbot label: -perf-regression Instruction countThis benchmark run did not return any relevant results for this metric. Max RSS (memory usage)ResultsThis is a less reliable metric that may be of interest but was not used to determine the overall result at the top of this comment.
CyclesThis benchmark run did not return any relevant results for this metric. |
I have been meaning to make this for quite a while, based off of this hackmd.
I'm not sure where to put this opt now that I've made it, so I'd appreciate suggestions on that!
It's also one long chain of statements, not sure if there's a more friendly format to make it.
r? @tmiasko
I would
r
oli but he's on leave so he suggested Ir
tmiasko or wesleywiser.