-
Notifications
You must be signed in to change notification settings - Fork 12.9k
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
More ptr metadata gvn #126541
More ptr metadata gvn #126541
Conversation
Some changes occurred to the CTFE / Miri engine cc @rust-lang/miri Some changes occurred to MIR optimizations cc @rust-lang/wg-mir-opt |
_7 = PtrMetadata(_6); | ||
StorageDead(_6); | ||
_8 = <std::ops::Range<usize> as SliceIndex<[T]>>::get_unchecked_mut::precondition_check(_3, _4, move _7) -> [return: bb1, unwind unreachable]; | ||
_6 = PtrMetadata(_1); |
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.
Note here how it can grab the length from the &mut [u32]
directly, and thus the cast to *const [u32]
can completely disappear, saving a statement and a local.
This comment has been minimized.
This comment has been minimized.
Some changes occurred in coverage tests. cc @Zalathar |
Since this touches |
This comment has been minimized.
This comment has been minimized.
More ptr metadata gvn There's basically 3 parts to this PR. 1. Allow references as arguments to `UnOp::PtrMetadata` This is a MIR semantics addition, so r? mir Rather than just raw pointers, also allow references to be passed to `PtrMetadata`. That means the length of a slice can be just `PtrMetadata(_1)` instead of also needing a ref-to-pointer statement (`_2 = &raw *_1` + `PtrMetadata(_2)`). AFAIK there should be no provenance or tagging implications of looking at the *metadata* of a pointer, and the code in the backends actually already supported it (other than a debug assert, given that they don't care about ptr vs reference, really), so we might as well allow it. 2. Simplify the argument to `PtrMetadata` in GVN Because the specific kind of pointer-like thing isn't that important, GVN can simplify all those details away. Things like `*const`-to-`*mut` casts and `&mut`-to-`&` reborrows are irrelevant, and skipping them lets it see more interesting things. cc `@cjgillot` Notably, unsizing casts for arrays. GVN supported that for `Len`, and now it sees it for `PtrMetadata` as well, allowing `PtrMetadata(pointer)` to become a constant if that pointer came from an array-to-slice unsizing, even through a bunch of other possible steps. 3. Replace `NormalizeArrayLen` with GVN The `NormalizeArrayLen` pass hasn't been running even in optimized builds for well over a year, and it turns out that GVN -- which *is* on in optimized builds -- can do everything it was trying to do. So the code for the pass is deleted, but the tests are kept, just changed to the different pass. As part of this, `LowerSliceLen` was changed to emit `PtrMetadata(_1)` instead of `Len(*_1)`, a small step on the road to eventually eliminating `Rvalue::Len`.
☀️ Try build successful - checks-actions |
This comment has been minimized.
This comment has been minimized.
Finished benchmarking commit (bcb40db): comparison URL. Overall result: ❌✅ regressions and improvements - ACTION NEEDEDBenchmarking this pull request likely means that it is perf-sensitive, so we're automatically marking it as not fit for rolling up. While you can manually mark this PR as fit for rollup, we strongly recommend not doing so since this PR may lead to changes in compiler perf. Next Steps: If you can justify the regressions found in this try perf run, please indicate this with @bors rollup=never Instruction countThis is a highly reliable metric that was used to determine the overall result at the top of this comment.
Max RSS (memory usage)Results (primary -1.2%)This 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.
CyclesResults (primary 0.3%, secondary 7.0%)This 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.
Binary sizeResults (primary 0.0%)This 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.
Bootstrap: 672.776s -> 674.201s (0.21%) |
} | ||
break; | ||
} | ||
} |
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.
Can all this go in simplify_unary
?
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.
Took some more rejiggering, because it couldn't with its existing signature, but done.
from, | ||
to, | ||
} = value | ||
&& from.builtin_deref(true) == to.builtin_deref(true) |
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.
Could you add a comment for this check?
Should we handle the case of both being slices of different element types?
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.
Apparently there's a (relatively) new helper that makes this plausible; yay! Done, and added new negative tests to make sure that metadata-changing casts don't get picked up by it.
// so earlier things can just `bug!` on it. | ||
self.fail(location, "PtrMetadata should be in runtime MIR only"); | ||
} | ||
|
||
check_kinds!(a, "Cannot PtrMetadata non-pointer type {:?}", ty::RawPtr(..)); |
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 doc comment should also be updated.
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.
Thanks; good callout. Done.
EDIT: Oh, and editing that file is what triggers the "hey someone changed MIR" pings :)
72cda61
to
7d15cf2
Compare
This PR changes MIR cc @oli-obk, @RalfJung, @JakobDegen, @davidtwco, @celinval, @vakaras |
7d15cf2
to
eec1b4b
Compare
☔ The latest upstream changes (presumably #126308) made this pull request unmergeable. Please resolve the merge conflicts. |
eec1b4b
to
525b5c3
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.
Some nits on the mir-opt changes. r=me on those when the mir semantics addition is approved.
std::intrinsics::ptr_metadata(x) | ||
} | ||
|
||
#[custom_mir(dialect = "runtime")] |
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.
This test is a bit tricky, could you add a small explanation why each case must work as shown?
if from.builtin_deref(true)?.ptr_metadata_ty_or_tail(self.tcx, |t| t) | ||
== to.builtin_deref(true)?.ptr_metadata_ty_or_tail(self.tcx, |t| t) => |
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.
Should we pass a normalization routine with our param_env? Or is it just being pedantic?
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 add a FIXME to consider it. I'm confident we don't need it, as if something needs normalizing and it doesn't happen we'll just not do this optimization.
Maybe it'd trigger sometimes, though? But it might also be that the types we get from the Cast
are already about as normalized as we can do in a MIR pass anyway, since we don't have a monomorphization context and thus might still end up with projections or whatever...
.. | ||
}, | ||
) if let ty::Slice(..) = to.builtin_deref(true).unwrap().kind() | ||
&& let ty::Array(_, len) = from.builtin_deref(true).unwrap().kind() => |
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.
Nit: why do we unwrap()
the result of builtin_deref here, while we ?
earlier?
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.
Should probably be an unwrap again. I'll change it; I'm just sad because rustfmt makes it really ugly.
This seems entirely uncontroversial to me from a MIR semantics / opsem perspective, so fine for me. |
No behaviour changes.
525b5c3
to
511bd8b
Compare
`PtrMetadata` doesn't care about `*const`/`*mut`/`&`/`&mut`, so GVN away those casts in its argument. This includes updating MIR to allow calling PtrMetadata on references too, not just raw pointers. That means that `[T]::len` can be just `_0 = PtrMetadata(_1)`, for example. # Conflicts: # tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-abort.mir # tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-unwind.mir
GVN is actually on in release, and covers all the same things (or more), with `LowerSliceLen` changed to produce `PtrMetadata`.
511bd8b
to
55d1337
Compare
@bors r=cjgillot |
☀️ Test successful - checks-actions |
Finished benchmarking commit (e32ea48): comparison URL. Overall result: ❌✅ regressions and improvements - ACTION NEEDEDNext Steps: If you can justify the regressions found in this perf run, please indicate this with @rustbot label: +perf-regression Instruction countThis is a highly reliable metric that was used to determine the overall result at the top of this comment.
Max RSS (memory usage)Results (primary 0.8%, secondary 3.9%)This 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.
CyclesResults (primary -1.4%)This 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.
Binary sizeResults (primary 0.0%, secondary 0.3%)This 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.
Bootstrap: 698.008s -> 696.377s (-0.23%) |
Some small wins and losses in each category, which roughly balance out. @rustbot label: +perf-regression-triaged |
There's basically 3 parts to this PR.
UnOp::PtrMetadata
This is a MIR semantics addition, so
r? mir
Rather than just raw pointers, also allow references to be passed to
PtrMetadata
. That means the length of a slice can be justPtrMetadata(_1)
instead of also needing a ref-to-pointer statement (_2 = &raw *_1
+PtrMetadata(_2)
).AFAIK there should be no provenance or tagging implications of looking at the metadata of a pointer, and the code in the backends actually already supported it (other than a debug assert, given that they don't care about ptr vs reference, really), so we might as well allow it.
PtrMetadata
in GVNBecause the specific kind of pointer-like thing isn't that important, GVN can simplify all those details away. Things like
*const
-to-*mut
casts and&mut
-to-&
reborrows are irrelevant, and skipping them lets it see more interesting things.cc @cjgillot
Notably, unsizing casts for arrays. GVN supported that for
Len
, and now it sees it forPtrMetadata
as well, allowingPtrMetadata(pointer)
to become a constant if that pointer came from an array-to-slice unsizing, even through a bunch of other possible steps.NormalizeArrayLen
with GVNThe
NormalizeArrayLen
pass hasn't been running even in optimized builds for well over a year, and it turns out that GVN -- which is on in optimized builds -- can do everything it was trying to do.So the code for the pass is deleted, but the tests are kept, just changed to the different pass.
As part of this,
LowerSliceLen
was changed to emitPtrMetadata(_1)
instead ofLen(*_1)
, a small step on the road to eventually eliminatingRvalue::Len
.