-
Notifications
You must be signed in to change notification settings - Fork 13.2k
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
Introduce unsafe offset_from on pointers #49297
Conversation
Adds intrinsics::exact_div to take advantage of the unsafe, which reduces the implementation from ```asm sub rcx, rdx mov rax, rcx sar rax, 63 shr rax, 62 lea rax, [rax + rcx] sar rax, 2 ret ``` down to ```asm sub rcx, rdx sar rcx, 2 mov rax, rcx ret ``` (for `*const i32`)
r? @dtolnay (rust_highfive has picked a reviewer for you, use r? to override) |
src/libcore/ptr.rs
Outdated
assert!(0 < pointee_size && pointee_size <= isize::max_value() as usize); | ||
|
||
// FIXME: can this be nuw/nsw? | ||
let d = isize::wrapping_sub(self as _, other as _); |
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 can't be nuw
because the result might be a negative value.
It can't be nsw
either because an allocation may straddle the boundary between ISIZE_MAX
(0x7fffffff) and ISIZE_MIN
(0x80000000).
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 agree. nuw
and nsw
force both the result and the operands to have the same interpretation as each other. What you'd really want here is a way to say that the operands have an unsigned interpretation, while the result has a signed interpretation, however there's currently no way to express that in LLVM.
@@ -343,6 +343,12 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bx: &Builder<'a, 'tcx>, | |||
"overflowing_add" => bx.add(args[0].immediate(), args[1].immediate()), | |||
"overflowing_sub" => bx.sub(args[0].immediate(), args[1].immediate()), | |||
"overflowing_mul" => bx.mul(args[0].immediate(), args[1].immediate()), | |||
"exact_div" => | |||
if signed { | |||
bx.exactsdiv(args[0].immediate(), args[1].immediate()) |
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.
exactsdiv
seems to be missing?
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 turned out to already exist: https://github.com/rust-lang/rust/pull/49297/files#diff-89b470c8d50892235012a9fffdb50d7cR361
/// | ||
/// let a = [0; 5]; | ||
/// let ptr1: *const i32 = &a[1]; | ||
/// let ptr2: *const i32 = &a[3]; |
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 will panic at runtime. You do this a few other places as well. You should probably use get_unchecked
? There's no actual mention of UB if you index out of bounds, so, I don't think it's an issue.
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.
Huh? a
is an array of length 5, so a[3]
is not out of bounds.
(But if it was, get_unchecked
would be UB because it uses offset
, not wrapping_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.
I, uh, may be too used to OCaml, sorry -.-
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.
Also, offset
works with pointers which are one past the end.
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 yeah if Edit: Uh, yeah, see belowa
had length 2 then that would have been fine.
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.
Actually, I'm just being stupid, array indexing is zero-based lol. Sorry, I should not comment when I'm tired :P
It was added 32 days after LLVM 3.9 shipped.
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 good to me. Thanks!
I agree with the discussion in the tracking issue that the safe wrapping one seems suspicious, but I think it is fine to see how it gets used and revisit before stabilization.
@bors r+ |
📌 Commit 6264952 has been approved by |
Introduce unsafe offset_from on pointers Adds intrinsics::exact_div to take advantage of the unsafe, which reduces the implementation from ```asm sub rcx, rdx mov rax, rcx sar rax, 63 shr rax, 62 lea rax, [rax + rcx] sar rax, 2 ret ``` down to ```asm sub rcx, rdx sar rcx, 2 mov rax, rcx ret ``` (for `*const i32`) See discussion on the `offset_to` tracking issue #41079 Some open questions - Would you rather I split the intrinsic PR from the library PR? - Do we even want the safe version of the API? #41079 (comment) I've added some text to its documentation that even if it's not UB, it's useless to use it between pointers into different objects. and todos - [x] ~~I need to make a codegen test~~ Done - [x] ~~Can the subtraction use nsw/nuw?~~ No, it can't #49297 (comment) - [x] ~~Should there be `usize` variants of this, like there are now `add` and `sub` that you almost always want over `offset`? For example, I imagine `sub_ptr` that returns `usize` and where it's UB if the distance is negative.~~ Can wait for later; C gives a signed result #41079 (comment), so we might as well, and this existing to go with `offset` makes sense.
☀️ Test successful - status-appveyor, status-travis |
Adds intrinsics::exact_div to take advantage of the unsafe, which reduces the implementation from
down to
(for
*const i32
)See discussion on the
offset_to
tracking issue #41079Some open questions
and todos
I need to make a codegen testDoneCan the subtraction use nsw/nuw?No, it can't Introduce unsafe offset_from on pointers #49297 (comment)Should there beCan wait for later; C gives a signed result Tracking issue for ptr::offset_from (feature: ptr_offset_from) #41079 (comment), so we might as well, and this existing to go withusize
variants of this, like there are nowadd
andsub
that you almost always want overoffset
? For example, I imaginesub_ptr
that returnsusize
and where it's UB if the distance is negative.offset
makes sense.