-
Notifications
You must be signed in to change notification settings - Fork 13k
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
Bounds-check with PtrMetadata instead of Len in MIR #133734
Bounds-check with PtrMetadata instead of Len in MIR #133734
Conversation
Some changes occurred to MIR optimizations cc @rust-lang/wg-mir-opt Some changes occurred to the CTFE machinery cc @rust-lang/wg-const-eval |
- _7 = Len((*_2)); | ||
- _8 = Lt(copy _6, copy _7); | ||
- assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, copy _6) -> [success: bb1, unwind unreachable]; | ||
+ _7 = const 3_usize; | ||
+ _8 = const true; | ||
+ assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> [success: bb1, unwind unreachable]; |
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 ended up just deleting this test, which seemed fine to me because GVN can do similar things to this, and DataflowConstProp is off in release anyway.
_11 = Len((*_1)); | ||
_12 = Lt(copy _10, copy _11); | ||
assert(move _12, "index out of bounds: the length is {} but the index is {}", move _11, copy _10) -> [success: bb6, unwind unreachable]; | ||
_11 = Lt(copy _10, copy _3); | ||
assert(move _11, "index out of bounds: the length is {} but the index is {}", copy _3, copy _10) -> [success: bb6, unwind unreachable]; |
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.
And overall the MIR seems slightly better after this PR, since [T]::len
had already moved to PtrMetadata
, and thus using it here too means that GVN can dedup the PtrMetadata
from the bounds check with the one from the .len()
call in the source.
This comment has been minimized.
This comment has been minimized.
Looks like I need to rethink this, because it seems borrowck and initialization checking are somehow coupled to this lowering. EDIT: actually, maybe I just need a fake read. |
2471745
to
a7f9bf7
Compare
This comment has been minimized.
This comment has been minimized.
a7f9bf7
to
90b3895
Compare
The Miri subtree was changed cc @rust-lang/miri |
90b3895
to
612adbb
Compare
//~[stack]^ ERROR: /write access .* tag does not exist in the borrow stack/ | ||
//~[stack]^ ERROR: /trying to retag .+ for SharedReadOnly permission .+ tag does not exist in the borrow stack for this location/ |
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.
@RalfJung I think what's happened here is that SB is now failing "on" the read of the slice length for the bounds check, before it gets to trying to write, thus it mentioning SharedReadOnly
instead of "write access", which seems at least plausibly fine. But please double-check that I didn't blow this up in some horrible way 😬
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.
Hm, yeah as you say it seems to fail on a read / retag-for-read now, instead of a write. It is a bit surprising that this would change now. How did the MIR change here?
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.
Would be good to add a slice index expression in mir-opt/retag.rs
so that we can see how this looks like with retagging.
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.
Because it's a &mut [_]
, it changed from doing the bounds check as
_2 = Len(*_1);
_3 = Lt(const 1_usize, _2)
assert(_3, …);
to
_4 = &raw const *_1;
_2 = PtrMetadata(move _4);
_3 = Lt(const 1_usize, _2)
assert(_3, …);
(It's not just PtrMetadata(copy _1)
because there could be a projection [like Len((*_1).3)
] and because that copy
on a &mut
ends up breaking borrowck.)
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, yeah the &raw const
here is relevant for Stacked Borrows -- it basically acts as a read on the entire slice. That is a bit unfortunate since so far, for slice accesses, we didn't do such a whole-slice retag. I think ideally we would not add a retag to these raw reborrows.
Is there any way for the retag pass to recognize these reborrows? Like, are they marked as syntactic sugar somewhere, or so? I recall we do that for some constructs, but I am not actually sure how it is represented.
Long-term I hope we can change SB to make raw retags true NOPs, but that will require a bit more work.
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, no, the read I added to the array case has FakeReadCause::ForIndex
, but nothing for the slice case.
I guess if I was to mark the &raw const
as something it'd be in the SourceInfo
that I'd do that, by marking its span somehow?
Alternatively, AFAIK this is always dealing in a place where the projection chain starts with a deref, like (*_1).3
. So is there a way in MIR building to emit just a PtrMetadata(copy _1)
that always works? The problem I hit is that when _1
is a &mut [_]
, that blows up later in MIR borrowck, thus why I added the &raw const
in the first place.
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 afraid I don't know much about MIR borrowck.
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 guess if I was to mark the &raw const as something it'd be in the SourceInfo that I'd do that, by marking its span somehow?
Yeah I think that's how the desugaring markers usually work, but I am not sure.
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.
LGTM, r=me if the issue with the Miri test is resolved
Some changes occurred to the CTFE / Miri interpreter cc @rust-lang/miri |
if !place_base_raw { | ||
if !place_base_raw | ||
&& span.desugaring_kind() != Some(DesugaringKind::IndexBoundsCheckReborrow) | ||
{ | ||
// If this was not already raw, it needs retagging. | ||
// Unless it's the `PtrMetadata(&raw const *_n)` from indexing. | ||
val = M::retag_ptr_value(self, mir::RetagKind::Raw, &val)?; | ||
} |
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.
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.
As mentioned before, please add a slice index expression to mir-opt/retag.rs
so one can see what the final MIR looks like.
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.
Oh never mind, I forgot that we don't have these retags in MIR any more.
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.
Yeah this is kind of a hack but it works, thanks!
Co-authored-by: Ralf Jung <post@ralfj.de>
@bors r=davidtwco,RalfJung |
…data, r=davidtwco,RalfJung Bounds-check with PtrMetadata instead of Len in MIR Rather than emitting `Len(*_n)` in array index bounds checks, emit `PtrMetadata(copy _n)` instead -- with some asterisks for arrays and `&mut` that need it to be done slightly differently. We're getting pretty close to removing `Len` entirely, actually. I think just one more PR after this (for slice drop shims). r? mir
@bors rollup=never |
☀️ Test successful - checks-actions |
Finished benchmarking commit (b57d93d): comparison URL. Overall result: ❌✅ regressions and improvements - please read the text belowOur benchmarks found a performance regression caused by this PR. Next Steps:
@rustbot label: +perf-regression Instruction countThis is the most reliable metric that we have; it was used to determine the overall result at the top of this comment. However, even this metric can sometimes exhibit noise.
Max RSS (memory usage)Results (primary 3.2%, secondary -0.1%)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.1%)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.1%)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: 768.736s -> 772.313s (0.47%) |
Single tiny regression, otherwise tiny improvements. @rustbot label: +perf-regression-triaged |
@@ -1163,6 +1163,9 @@ pub enum DesugaringKind { | |||
WhileLoop, | |||
/// `async Fn()` bound modifier | |||
BoundModifier, | |||
/// Marks a `&raw const *_1` needed as part of getting the length of a mutable | |||
/// slice for the bounds check, so that MIRI's retag handling can recognize it. | |||
IndexBoundsCheckReborrow, |
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.
Span should definitely not be used like this. Span desugarings should only ever be used for diagnostics and things like that -- making miri rely on this behavior seems really bad. If we need to track certain locals for the purposes of some special miri hack, this needs to be recorded in the MIR body separately.
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.
It's a pretty bad hack, yeah. Medium-term I hope that Miri can entirely stop doing retagging on &raw
, but this currently runs into issues... so not sure if it's worth spending a lot of effort on the proper thing.
@@ -463,6 +463,9 @@ impl<'tcx> Const<'tcx> { | |||
let const_val = tcx.valtree_to_const_val((ty, valtree)); | |||
Self::Val(const_val, ty) | |||
} | |||
ty::ConstKind::Unevaluated(ty::UnevaluatedConst { def, args }) => { |
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 is not correct, and there's no justification here? What is this for?
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.
Specifically, there's a distinction between ty::ConstKind::Unevaluated(ty::UnevaluatedConst(..))
and mir::ConstKind::Unevaluated(..)
and I think this may be getting that wrong. But generally randomly changing a function to do something different without asking why it's that way that seems like it may introduce subtle bugs 🤔
Temporarily bring back `Rvalue::Len` r? `@compiler-errors` as requested in rust-lang#135671 (comment) > However, in the mean time, I'd rather we not crunch trying to find and more importantly validate the soundness of a solution 🤔 Agreed. To fix the IMO P-critical rust-lang#135671 for which we somehow didn't have test coverage, this PR temporarily reverts: - rust-lang#133734 - its bugfix rust-lang#134371 - rust-lang#134330 cc `@scottmcm` I added the few samples from that issue as a test, but we can add more in the future, in particular it seems `@steffahn` [will work on that](rust-lang#135671 (comment)). Fixes rust-lang#135671. And if we want to land this, it should also be nominated for beta backport.
…ptrmetadata, r=davidtwco,RalfJung" This reverts commit 122a55b.
…ptrmetadata, r=davidtwco,RalfJung" This reverts commit 122a55b.
…ptrmetadata, r=davidtwco,RalfJung" This reverts commit 122a55b.
…ptrmetadata, r=davidtwco,RalfJung" This reverts commit 122a55b.
Rather than emitting
Len(*_n)
in array index bounds checks, emitPtrMetadata(copy _n)
instead -- with some asterisks for arrays and&mut
that need it to be done slightly differently.We're getting pretty close to removing
Len
entirely, actually. I think just one more PR after this (for slice drop shims).r? mir