-
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
Use MIR's Offset
for pointer add
too
#110837
Conversation
31935ae
to
0e9c35e
Compare
This comment has been minimized.
This comment has been minimized.
0e9c35e
to
c59b19c
Compare
This comment has been minimized.
This comment has been minimized.
c59b19c
to
ba11a57
Compare
@bors try @rust-timer queue |
This comment has been minimized.
This comment has been minimized.
⌛ Trying commit ba11a57d8732f24440bc0cea73d9349ff1bfe1f2 with merge f18e18871f6876c0ae22f4f4939e847cb0a3eaf4... |
☀️ Try build successful - checks-actions |
This comment has been minimized.
This comment has been minimized.
This comment was marked as outdated.
This comment was marked as outdated.
@bors try @rust-timer queue |
This comment has been minimized.
This comment has been minimized.
⌛ Trying commit 0864da33e625dd85a381598a6ec9779b8cc5f0a8 with merge c677fe4f1af9780ecb80c7d1c453d9de4051aadd... |
☀️ Try build successful - checks-actions |
This comment has been minimized.
This comment has been minimized.
Finished benchmarking commit (c677fe4f1af9780ecb80c7d1c453d9de4051aadd): 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)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.
CyclesResultsThis 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.
|
4db04d4
to
1c1c8e4
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.
Changes look fine to me other than one question, and then I am not sure if this perf regression is actually worth caring about or not.
I thought about it more. I think the emitted code is overall simpler and the codegen changes are yeah, more of a side-effect of the usage of the @bors r+ |
📌 Commit 1c1c8e442add0f46905a57a25a6cba52b8b0c54d has been approved by It is now in the queue for this repository. |
@@ -215,7 +215,8 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { | |||
|
|||
sym::type_name => (1, Vec::new(), tcx.mk_static_str()), | |||
sym::type_id => (1, Vec::new(), tcx.types.u64), | |||
sym::offset | sym::arith_offset => ( | |||
sym::offset => (2, vec![param(0), param(1)], param(0)), | |||
sym::arith_offset => ( |
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.
Is arith_offset
not changed because we don't have a version of it in MIR?
Makes me wander if we should try intrinsicing other offset like functions like {byte,wrapping,wrapping_byte}_{add,sub,offset}
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.
@WaffleLapkin The weird thing about byte_add
is that it works on fat pointers. So it ends up quite a bit more complex than offset
. I'm not sure if that's worth doing as an intrinsic or not. For the data part of it, cast-then-offset
-then-cast of course works fine.
As for sub
, maybe we should start by changing it from wrapping_neg
to unchecked_neg
, especially after #112238...
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, but wouldn't byte_add
be just self.data += x
? Doesn't sound like it's too hard for an intrinsic...
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.
@WaffleLapkin Is perhaps your email client catching up on some ancient messages? Or are looking at old stuff 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.
@scottmcm I cleared up old notifications that I were putting off for a long time 😄
1c1c8e4
to
e1da77c
Compare
Just made the requested comment change. @bors r=compiler-errors |
☀️ Test successful - checks-actions |
Finished benchmarking commit (43a7802): 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)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.
CyclesResultsThis 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.
|
Ah, those perf results make more sense to me. A few improvements to check/debug, net improvement for opt despite some regressions, and a small improvement to binary size (mostly in debug). |
Wins exceed losses. @rustbot label: +perf-regression-triaged |
#[must_use = "returns a new pointer rather than modifying its argument"] | ||
#[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")] | ||
#[rustc_nounwind] | ||
pub fn offset<Ptr, Delta>(dst: Ptr, offset: Delta) -> Ptr; |
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.
When changing intrinsics, please make sure to always Cc the opsem and miri teams! These are language primitives, a bunch of places need to typically be adjusted to make everything fit again. In this case, this PR made the Miri logic all wrong since it will still always assume the offset to be an isize
-- thus missing UB, which is a critical bug in Miri.
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.
Sorry about that, Ralf! I'll keep it in mind next time.
When the validator was explicitly allowing both isize and usize as argument types, I'd assumed it was handling the usize in the "obvious" way, but clearly I should have checked.
CTFE handles this, but wrong -- it will always transmute the argument to |
…ottmcm ptr::add/sub: do not claim equivalence with `offset(c as isize)` In rust-lang#110837, the `offset` intrinsic got changed to also allow a `usize` offset parameter. The intention is that this will do an unsigned multiplication with the size, and we have UB if that overflows -- and we also have UB if the result is larger than `usize::MAX`, i.e., if a subsequent cast to `isize` would wrap. ~~The LLVM backend sets some attributes accordingly.~~ This updates the docs for `add`/`sub` to match that intent, in preparation for adjusting codegen to exploit this UB. We use this opportunity to clarify what the exact requirements are: we compute the offset using mathematical multiplication (so it's no problem to have an `isize * usize` multiplication, we just multiply integers), and the result must fit in an `isize`. Cc `@rust-lang/opsem` `@nikic` rust-lang#130239 updates Miri to detect this UB. `sub` still has some cases of UB not reflected in the underlying intrinsic semantics (and Miri does not catch): when we subtract `usize::MAX`, then after casting to `isize` that's just `-1` so we end up adding one unit without noticing any UB, but actually the offset we gave does not fit in an `isize`. Miri will currently still not complain for such cases: ```rust fn main() { let x = &[0i32; 2]; let x = x.as_ptr(); // This should be UB, we are subtracting way too much. unsafe { x.sub(usize::MAX).read() }; } ``` However, the LLVM IR we generate here also is UB-free. This is "just" library UB but not language UB. Cc `@saethlin;` might be worth adding precondition checks against overflow on `offset`/`add`/`sub`? Fixes rust-lang#130211
Rollup merge of rust-lang#130229 - RalfJung:ptr-offset-unsigned, r=scottmcm ptr::add/sub: do not claim equivalence with `offset(c as isize)` In rust-lang#110837, the `offset` intrinsic got changed to also allow a `usize` offset parameter. The intention is that this will do an unsigned multiplication with the size, and we have UB if that overflows -- and we also have UB if the result is larger than `usize::MAX`, i.e., if a subsequent cast to `isize` would wrap. ~~The LLVM backend sets some attributes accordingly.~~ This updates the docs for `add`/`sub` to match that intent, in preparation for adjusting codegen to exploit this UB. We use this opportunity to clarify what the exact requirements are: we compute the offset using mathematical multiplication (so it's no problem to have an `isize * usize` multiplication, we just multiply integers), and the result must fit in an `isize`. Cc `@rust-lang/opsem` `@nikic` rust-lang#130239 updates Miri to detect this UB. `sub` still has some cases of UB not reflected in the underlying intrinsic semantics (and Miri does not catch): when we subtract `usize::MAX`, then after casting to `isize` that's just `-1` so we end up adding one unit without noticing any UB, but actually the offset we gave does not fit in an `isize`. Miri will currently still not complain for such cases: ```rust fn main() { let x = &[0i32; 2]; let x = x.as_ptr(); // This should be UB, we are subtracting way too much. unsafe { x.sub(usize::MAX).read() }; } ``` However, the LLVM IR we generate here also is UB-free. This is "just" library UB but not language UB. Cc `@saethlin;` might be worth adding precondition checks against overflow on `offset`/`add`/`sub`? Fixes rust-lang#130211
Status: draft while waiting for #110822 to land, since this is built atop that.r? @ghostCanonical Rust code has mostly moved to
add
/sub
on pointers, which takeusize
, instead ofoffset
which takesisize
. (And, relatedly, whensub_ptr
was added it turned out it replaced every single in-tree use ofoffset_from
, becauseusize
is just so much more useful thanisize
in Rust.)Unfortunately,
intrinsics::offset
could only accept*const
andisize
, so there's a huge amount of type conversions back and forth being done. They're identity conversions in the backend, but still end up producing quite a lot of unhelpful MIR.This PR changes
intrinsics::offset
to accept*const
and*mut
along withisize
andusize
. Conveniently, the backends and CTFE already handle this, since MIR'sBinOp::Offset
already supports all four combinations.To demonstrate the difference, I added some
mir-opt/pre-codegen/
tests around slice indexing. Here's the difference to[T]::get_mut
, since it uses<*mut _>::add
internally:1c1c8e4#diff-a841b6a4538657add3f39bc895744331453d0625e7aace128b1f604f0b63c8fdR80