Skip to content
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

Tracking Issue for int_roundings #88581

Open
jhpratt opened this issue Sep 2, 2021 · 171 comments
Open

Tracking Issue for int_roundings #88581

jhpratt opened this issue Sep 2, 2021 · 171 comments
Labels
C-tracking-issue Category: An issue tracking the progress of sth. like the implementation of an RFC disposition-merge This issue / PR is in PFCP or FCP with a disposition to merge it. finished-final-comment-period The final comment period is finished for this PR / Issue. T-libs-api Relevant to the library API team, which will review and decide on the PR/issue.

Comments

@jhpratt
Copy link
Member

jhpratt commented Sep 2, 2021

Feature gate: #![feature(int_roundings)]

This is a tracking issue for the div_floor, div_ceil, next_multiple_of, and checked_multiple_of methods on all integer types.

Public API

impl {integer} {
    #[unstable]
    pub const fn div_floor(self, rhs: Self) -> Self;
}

impl {signed integer} {
    #[unstable]
    pub const fn div_ceil(self, rhs: Self) -> Self;

    #[unstable]
    pub const fn next_multiple_of(self, rhs: Self) -> Self;

    #[unstable]
    pub const fn checked_next_multiple_of(self, rhs: Self) -> Option<Self>;
}

impl {unsigned integer} {
    #[stable(since = "1.73.0")]
    pub const fn div_ceil(self, rhs: Self) -> Self;

    #[stable(since = "1.73.0")]
    pub const fn next_multiple_of(self, rhs: Self) -> Self;

    #[stable(since = "1.73.0")]
    pub const fn checked_next_multiple_of(self, rhs: Self) -> Option<Self>;
}

Steps / History

Unresolved Questions

  • None yet.
@jhpratt jhpratt added C-tracking-issue Category: An issue tracking the progress of sth. like the implementation of an RFC T-libs-api Relevant to the library API team, which will review and decide on the PR/issue. labels Sep 2, 2021
jhpratt added a commit to jhpratt/rust that referenced this issue Sep 2, 2021
m-ou-se added a commit to m-ou-se/rust that referenced this issue Sep 2, 2021
Implement rust-lang#88581

See rust-lang#88581 for details. This API was discussed on Zulip.

`@rustbot` label: +T-libs-api +S-waiting-on-review

r? `@joshtriplett`
bors added a commit to rust-lang-ci/rust that referenced this issue Sep 2, 2021
Rollup of 12 pull requests

Successful merges:

 - rust-lang#88177 (Stabilize std::os::unix::fs::chroot)
 - rust-lang#88505 (Use `unwrap_unchecked` where possible)
 - rust-lang#88512 (Upgrade array_into_iter lint to include Deref-to-array types.)
 - rust-lang#88532 (Remove single use variables)
 - rust-lang#88543 (Improve closure dummy capture suggestion in macros.)
 - rust-lang#88560 (`fmt::Formatter::pad`: don't call chars().count() more than one time)
 - rust-lang#88565 (Add regression test for issue 83190)
 - rust-lang#88567 (Remove redundant `Span` in `QueryJobInfo`)
 - rust-lang#88573 (rustdoc: Don't panic on ambiguous inherent associated types)
 - rust-lang#88582 (Implement rust-lang#88581)
 - rust-lang#88589 (Correct doc comments inside `use_expr_visitor.rs`)
 - rust-lang#88592 (Fix ICE in const check)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
@fourbytes
Copy link

Just updated to the latest nightly, looks like this feature breaks the num-bigint crate.

error[E0658]: use of unstable library feature 'int_roundings'
error[E0658]: use of unstable library feature 'int_roundings'
   --> /home/fourbytes/.cargo/registry/src/github.com-1ecc6299db9ec823/num-bigint-0.4.1/src/biguint.rs:398:45
    |
398 |                 let root_scale = extra_bits.div_ceil(&n64);
    |                                             ^^^^^^^^
    |
    = note: see issue #88581 <https://github.com/rust-lang/rust/issues/88581> for more information
    = help: add `#![feature(int_roundings)]` to the crate attributes to enable

error[E0308]: mismatched types
   --> /home/fourbytes/.cargo/registry/src/github.com-1ecc6299db9ec823/num-bigint-0.4.1/src/biguint.rs:398:54
    |
398 |                 let root_scale = extra_bits.div_ceil(&n64);
    |                                                      ^^^^ expected `u64`, found `&u64`
    |
help: consider removing the borrow
    |
398 -                 let root_scale = extra_bits.div_ceil(&n64);
398 +                 let root_scale = extra_bits.div_ceil(n64);
    |

error[E0658]: use of unstable library feature 'int_roundings'
  --> /home/fourbytes/.cargo/registry/src/github.com-1ecc6299db9ec823/num-bigint-0.4.1/src/biguint/convert.rs:70:10
   |
70 |         .div_ceil(&big_digit::BITS.into())
   |          ^^^^^^^^
   |
   = note: see issue #88581 <https://github.com/rust-lang/rust/issues/88581> for more information
   = help: add `#![feature(int_roundings)]` to the crate attributes to enable

error[E0308]: mismatched types
  --> /home/fourbytes/.cargo/registry/src/github.com-1ecc6299db9ec823/num-bigint-0.4.1/src/biguint/convert.rs:70:19
   |
70 |         .div_ceil(&big_digit::BITS.into())
   |                   ^^^^^^^^^^^^^^^^^^^^^^^ expected `u64`, found reference
   |
   = note:   expected type `u64`
           found reference `&_`
help: consider removing the borrow
   |
70 -         .div_ceil(&big_digit::BITS.into())
70 +         .div_ceil(big_digit::BITS.into())
   |

error[E0658]: use of unstable library feature 'int_roundings'
   --> /home/fourbytes/.cargo/registry/src/github.com-1ecc6299db9ec823/num-bigint-0.4.1/src/biguint/convert.rs:585:10
    |
585 |         .div_ceil(&u64::from(bits))
    |          ^^^^^^^^
    |
    = note: see issue #88581 <https://github.com/rust-lang/rust/issues/88581> for more information
    = help: add `#![feature(int_roundings)]` to the crate attributes to enable

error[E0308]: mismatched types
   --> /home/fourbytes/.cargo/registry/src/github.com-1ecc6299db9ec823/num-bigint-0.4.1/src/biguint/convert.rs:585:19
    |
585 |         .div_ceil(&u64::from(bits))
    |                   ^^^^^^^^^^^^^^^^ expected `u64`, found `&u64`
    |
help: consider removing the borrow
    |
585 -         .div_ceil(&u64::from(bits))
585 +         .div_ceil(u64::from(bits))
    |

error[E0658]: use of unstable library feature 'int_roundings'
   --> /home/fourbytes/.cargo/registry/src/github.com-1ecc6299db9ec823/num-bigint-0.4.1/src/biguint/convert.rs:613:10
    |
613 |         .div_ceil(&u64::from(bits))
    |          ^^^^^^^^
    |
    = note: see issue #88581 <https://github.com/rust-lang/rust/issues/88581> for more information
    = help: add `#![feature(int_roundings)]` to the crate attributes to enable

error[E0308]: mismatched types
   --> /home/fourbytes/.cargo/registry/src/github.com-1ecc6299db9ec823/num-bigint-0.4.1/src/biguint/convert.rs:613:19
    |
613 |         .div_ceil(&u64::from(bits))
    |                   ^^^^^^^^^^^^^^^^ expected `u64`, found `&u64`
    |
help: consider removing the borrow
    |
613 -         .div_ceil(&u64::from(bits))
613 +         .div_ceil(u64::from(bits))
    |

Some errors have detailed explanations: E0308, E0658.
For more information about an error, try `rustc --explain E0308`.
error: could not compile `num-bigint` due to 8 previous errors
warning: build failed, waiting for other jobs to finish...
error: build failed

@jhpratt
Copy link
Member Author

jhpratt commented Sep 3, 2021

That is considered acceptable breakage. Per RFC 1105, adding an inherent impl is a minor change.

catenacyber added a commit to catenacyber/num-bigint that referenced this issue Sep 3, 2021
catenacyber added a commit to catenacyber/num-bigint that referenced this issue Sep 3, 2021
catenacyber added a commit to catenacyber/num-bigint that referenced this issue Sep 3, 2021
bors bot added a commit to rust-num/num-bigint that referenced this issue Sep 3, 2021
219: rust: use explicitily Integer::div_ceil r=cuviper a=catenacyber

Fixes #218

cf rust-lang/rust#88581

Co-authored-by: Philippe Antoine <[email protected]>
Co-authored-by: Josh Stone <[email protected]>
bors bot added a commit to rust-num/num-bigint that referenced this issue Sep 3, 2021
219: rust: use explicitily Integer::div_ceil r=cuviper a=catenacyber

Fixes #218

cf rust-lang/rust#88581

Co-authored-by: Philippe Antoine <[email protected]>
Co-authored-by: Josh Stone <[email protected]>
cuviper pushed a commit to cuviper/num-bigint that referenced this issue Sep 3, 2021
@aidanhs
Copy link
Member

aidanhs commented Sep 4, 2021

Though technically not a breaking change, I wonder if it's worth delaying it landing in stable for a bit? "Everything that uses num-bigint" feels kinda large. I guess we'll see the scope of the breakage on a release-based crater run.

brooksprumo added a commit to solana-labs/solana that referenced this issue Sep 4, 2021
`cargo check` on nightly was erroring due to num-bigint:

```text
error[E0658]: use of unstable library feature 'int_roundings'
   --> [...]/.cargo/registry/src/github.com-1ecc6299db9ec823/num-bigint-0.3.1/src/biguint.rs:208:10
    |
208 |         .div_ceil(&big_digit::BITS.into())
    |          ^^^^^^^^
    |
    = note: see issue #88581 <rust-lang/rust#88581> for more information
    = help: add `#![feature(int_roundings)]` to the crate attributes to enable
```
brooksprumo added a commit to brooksprumo/solana that referenced this issue Sep 4, 2021
`cargo check` on nightly was erroring due to num-bigint:

```text
error[E0658]: use of unstable library feature 'int_roundings'
   --> [...]/.cargo/registry/src/github.com-1ecc6299db9ec823/num-bigint-0.3.1/src/biguint.rs:208:10
    |
208 |         .div_ceil(&big_digit::BITS.into())
    |          ^^^^^^^^
    |
    = note: see issue #88581 <rust-lang/rust#88581> for more information
    = help: add `#![feature(int_roundings)]` to the crate attributes to enable
```
mergify bot pushed a commit to solana-labs/solana that referenced this issue Sep 4, 2021
* Update num-bigint to 0.3.3

`cargo check` on nightly was erroring due to num-bigint:

```text
error[E0658]: use of unstable library feature 'int_roundings'
   --> [...]/.cargo/registry/src/github.com-1ecc6299db9ec823/num-bigint-0.3.1/src/biguint.rs:208:10
    |
208 |         .div_ceil(&big_digit::BITS.into())
    |          ^^^^^^^^
    |
    = note: see issue #88581 <rust-lang/rust#88581> for more information
    = help: add `#![feature(int_roundings)]` to the crate attributes to enable
```

* pr: update enum-ordinalize and educe
@jhpratt
Copy link
Member Author

jhpratt commented Sep 4, 2021

num-bigint has already cut a release to fix it on their end. I suggested reverting the initial implementation on Zulip when that was pointed out. Definitely worth waiting a bit for stabilization to let things settle.

@leonardo-m
Copy link

Before stabilizing these functions let's see if enough people use them often enough (otherwise it's wiser to remove them).

@jhpratt
Copy link
Member Author

jhpratt commented Sep 6, 2021

There's a well-established use for them via the num crate. A number of algorithms would use div_floor and div_ceil, and next_multiple_of is useful for things like block sizes. The use case absolutely exists.

JesseWright added a commit to JesseWright/smithy-rs that referenced this issue Sep 6, 2021
rust-lang/rust#88581 adds several new integer methods as inherent impls. These new methods are a breaking change accepted as a minor change. They already cause build failures with nightly and will eventually cause build failures with stable as well, unless rust-lang changes course. This uses `Integer::div_floor` explicitly to avoid accidentally calling the new nightly methods, same as done for rust-num/num-bigint#218.
@apiraino apiraino removed the to-announce Announce this issue on triage meeting label Aug 10, 2023
@jhpratt
Copy link
Member Author

jhpratt commented Aug 12, 2023

Now that FCP has completed, what is the actual API that was agreed upon? I can update the open PR (#94455), but I don't have the time to re-read this thread 😅

@joshtriplett
Copy link
Member

Unsigned only, and without div_floor.

@jhpratt
Copy link
Member Author

jhpratt commented Aug 12, 2023

PR has been updated to that effect.

matthiaskrgr added a commit to matthiaskrgr/rust that referenced this issue Aug 12, 2023
…joshtriplett

Partially stabilize `int_roundings`

This stabilizes the following:

```rust
impl uX {
    pub const fn div_ceil(self, rhs: Self) -> Self;
    pub const fn next_multiple_of(self, rhs: Self) -> Self;
    pub const fn checked_next_multiple_of(self, rhs: Self) -> Option<Self>;
}
```

This feature is tracked in rust-lang#88581.
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this issue Aug 12, 2023
…joshtriplett

Partially stabilize `int_roundings`

This stabilizes the following:

```rust
impl uX {
    pub const fn div_ceil(self, rhs: Self) -> Self;
    pub const fn next_multiple_of(self, rhs: Self) -> Self;
    pub const fn checked_next_multiple_of(self, rhs: Self) -> Option<Self>;
}
```

This feature is tracked in rust-lang#88581.
vDorst added a commit to vDorst/embassy that referenced this issue Aug 21, 2023
Currently next_multiple_of() is behinged a Feature gate: int_rounding.
See rust-lang/rust#88581
But it seems that this function is stablized in rust 1.73.
See rust-lang/rust#94455

Currently Embassy is still using nightly for many other unstable
features. So I do see an issue to use this function.
vDorst added a commit to vDorst/embassy that referenced this issue Aug 23, 2023
Currently next_multiple_of() is behinged a Feature gate: int_rounding.
See rust-lang/rust#88581
But it seems that this function is stablized in rust 1.73.
See rust-lang/rust#94455

Currently Embassy is still using nightly for many other unstable
features. So I do see an issue to use this function.
@lib-eramen
Copy link

I'm just stumbling on this feature right now and I can see that there's a tag that says FCP is completed (and conversation indicates that), so can we tick that one to-do item that's in the original comment? Just a nit-pick.

@jhpratt
Copy link
Member Author

jhpratt commented Feb 16, 2024

That FCP was for a partial stabilization.

@orlp
Copy link
Contributor

orlp commented Mar 19, 2024

I do not like that next_multiple_of goes in different directions based on the sign of the rhs for signed integers. I propose we add a second function, prev_multiple_of (which is generally useful for unsigned integers as well, and something I would like to add regardless).

Then I propose that next_multiple_of finds the multiple of rhs that is always greater or equal to lhs, and that prev_multiple_of finds the multiple of rhs that is always less than or equal to lhs, also for signed integers.

Note that this would mean nothing would change for unsigned::next_multiple_of, which is good since it's already stabilized, whereas signed::next_multiple_of is still unstable so can be changed.

@hsanzg
Copy link

hsanzg commented Jul 20, 2024

Are there any plans to add a NonZero{unsigned} version of checked_next_multiple_of? Given two positive integers, the result of this method is also positive when the rounding does not overflow. On the other hand, the wrapping behavior of {unsigned}::next_multiple_of can lead to a zero result in release mode (because zero is the trivial multiple of every integer). Specifically, I propose to add

  • An unsafe, NonZero-equivalent of {unsigned}::next_multiple_of called NonZero{unsigned}::unchecked_next_multiple_of that returns NonZero{unsigned}; and
  • A safe NonZero-equivalent of {unsigned}::checked_next_multiple_of called NonZero{unsigned}::next_multiple_of that returns Option<NonZero{unsigned}>, being None on overflow.

Example application: I've been working on a stack allocator, and I would've liked to represent the size of a stack as a NonZeroUsize. The methods proposed above would have been really useful to do alignment calculations, but I finally went with a size: usize variable since the sprinkling of NonZeroUsize.get calls is a bit cleaner than the alternative (implementing next_multiple_of myself, as in this library).

I think any NonZero{signed} version of [checked_]next_multiple_of would see less use in practice, but it could would make the standard library more uniform/predictable. The same applies to div_floor and div_ceil.

(I'm sorry in advance if this is not the proper place to discuss this issue. It could also be part of the nonzero_ops feature #84186.)

matthiaskrgr added a commit to matthiaskrgr/rust that referenced this issue Aug 28, 2024
docs: correct panic conditions for rem_euclid and similar functions

fixes rust-lang#128857

also fixes the documentation for functions behind the `int_roundings` feature (rust-lang#88581)
rust-timer added a commit to rust-lang-ci/rust that referenced this issue Aug 28, 2024
Rollup merge of rust-lang#129480 - lolbinarycat:euclid-docs, r=joboet

docs: correct panic conditions for rem_euclid and similar functions

fixes rust-lang#128857

also fixes the documentation for functions behind the `int_roundings` feature (rust-lang#88581)
bors added a commit to rust-lang-ci/rust that referenced this issue Sep 8, 2024
better implementation of signed div_floor/ceil

Tracking issue for signed `div_floor`/`div_ceil`: rust-lang#88581.

This PR improves the implementation of those two functions by adding a better branchless algorithm. Side-by-side comparison of `i32::div_floor` on x86-64:

```asm
div_floor_new:                               div_floor_old:
        push    rax                                  push    rax
        test    esi, esi                             test    esi, esi
        je      .LBB0_3                              je      .LBB1_6
        mov     eax, esi                             mov     eax, esi
        not     eax                                  not     eax
        lea     ecx, [rdi - 2147483648]              lea     ecx, [rdi - 2147483648]
        or      ecx, eax                             or      ecx, eax
        je      .LBB0_2                              je      .LBB1_7
        mov     eax, edi                             mov     eax, edi
        cdq                                          cdq
        idiv    esi                                  idiv    esi
        xor     esi, edi                             test    edx, edx
        sar     esi, 31                              setg    cl
        test    edx, edx                             test    esi, esi
        cmove   esi, edx                             sets    dil
        add     eax, esi                             test    dil, cl
        pop     rcx                                  jne     .LBB1_4
        ret                                          test    edx, edx
.LBB0_3:                                             setns   cl
        lea     rdi, [rip + .L__unnamed_1]           test    esi, esi
        call    qword ptr [rip + panic...]          setle   dl
.LBB0_2:                                             or      dl, cl
        lea     rdi, [rip + .L__unnamed_1]           jne     .LBB1_5
        call    qword ptr [rip + panic...]   .LBB1_4:
                                                     dec     eax
                                             .LBB1_5:
                                                     pop     rcx
                                                     ret
                                             .LBB1_6:
                                                     lea     rdi, [rip + .L__unnamed_2]
                                                     call    qword ptr [rip + panic...]
                                             .LBB1_7:
                                                     lea     rdi, [rip + .L__unnamed_2]
                                                     call    qword ptr [rip + panic...]
```

And on Aarch64:

```asm
_div_floor_new:                                   _div_floor_old:
        stp     x29, x30, [sp, #-16]!                     stp     x29, x30, [sp, #-16]!
        mov     x29, sp                                   mov     x29, sp
        cbz     w1, LBB0_4                                cbz     w1, LBB1_9
        mov     w8, #-2147483648                          mov     x8, x0
        cmp     w0, w8                                    mov     w9, #-2147483648
        b.ne    LBB0_3                                    cmp     w0, w9
        cmn     w1, #1                                    b.ne    LBB1_3
        b.eq    LBB0_5                                    cmn     w1, #1
LBB0_3:                                                   b.eq    LBB1_10
        sdiv    w8, w0, w1                        LBB1_3:
        msub    w9, w8, w1, w0                            sdiv    w0, w8, w1
        eor     w10, w1, w0                               msub    w8, w0, w1, w8
        asr     w10, w10, rust-lang#31                             tbz     w1, rust-lang#31, LBB1_5
        cmp     w9, #0                                    cmp     w8, #0
        csel    w9, wzr, w10, eq                          b.gt    LBB1_7
        add     w0, w9, w8                        LBB1_5:
        ldp     x29, x30, [sp], rust-lang#16                       cmp     w1, #1
        ret                                               b.lt    LBB1_8
LBB0_4:                                                   tbz     w8, rust-lang#31, LBB1_8
        adrp    x0, l___unnamed_1@PAGE            LBB1_7:
        add     x0, x0, l___unnamed_1@PAGEOFF             sub     w0, w0, #1
        bl      panic...                          LBB1_8:
LBB0_5:                                                   ldp     x29, x30, [sp], rust-lang#16
        adrp    x0, l___unnamed_1@PAGE                    ret
        add     x0, x0, l___unnamed_1@PAGEOFF     LBB1_9:
        bl      panic...                                  adrp    x0, l___unnamed_2@PAGE
                                                          add     x0, x0, l___unnamed_2@PAGEOFF
                                                          bl      panic...
                                                  LBB1_10:
                                                          adrp    x0, l___unnamed_2@PAGE
                                                          add     x0, x0, l___unnamed_2@PAGEOFF
                                                          bl      panic...
```
RalfJung pushed a commit to RalfJung/miri that referenced this issue Sep 10, 2024
better implementation of signed div_floor/ceil

Tracking issue for signed `div_floor`/`div_ceil`: rust-lang/rust#88581.

This PR improves the implementation of those two functions by adding a better branchless algorithm. Side-by-side comparison of `i32::div_floor` on x86-64:

```asm
div_floor_new:                               div_floor_old:
        push    rax                                  push    rax
        test    esi, esi                             test    esi, esi
        je      .LBB0_3                              je      .LBB1_6
        mov     eax, esi                             mov     eax, esi
        not     eax                                  not     eax
        lea     ecx, [rdi - 2147483648]              lea     ecx, [rdi - 2147483648]
        or      ecx, eax                             or      ecx, eax
        je      .LBB0_2                              je      .LBB1_7
        mov     eax, edi                             mov     eax, edi
        cdq                                          cdq
        idiv    esi                                  idiv    esi
        xor     esi, edi                             test    edx, edx
        sar     esi, 31                              setg    cl
        test    edx, edx                             test    esi, esi
        cmove   esi, edx                             sets    dil
        add     eax, esi                             test    dil, cl
        pop     rcx                                  jne     .LBB1_4
        ret                                          test    edx, edx
.LBB0_3:                                             setns   cl
        lea     rdi, [rip + .L__unnamed_1]           test    esi, esi
        call    qword ptr [rip + panic...]          setle   dl
.LBB0_2:                                             or      dl, cl
        lea     rdi, [rip + .L__unnamed_1]           jne     .LBB1_5
        call    qword ptr [rip + panic...]   .LBB1_4:
                                                     dec     eax
                                             .LBB1_5:
                                                     pop     rcx
                                                     ret
                                             .LBB1_6:
                                                     lea     rdi, [rip + .L__unnamed_2]
                                                     call    qword ptr [rip + panic...]
                                             .LBB1_7:
                                                     lea     rdi, [rip + .L__unnamed_2]
                                                     call    qword ptr [rip + panic...]
```

And on Aarch64:

```asm
_div_floor_new:                                   _div_floor_old:
        stp     x29, x30, [sp, #-16]!                     stp     x29, x30, [sp, #-16]!
        mov     x29, sp                                   mov     x29, sp
        cbz     w1, LBB0_4                                cbz     w1, LBB1_9
        mov     w8, #-2147483648                          mov     x8, x0
        cmp     w0, w8                                    mov     w9, #-2147483648
        b.ne    LBB0_3                                    cmp     w0, w9
        cmn     w1, #1                                    b.ne    LBB1_3
        b.eq    LBB0_5                                    cmn     w1, #1
LBB0_3:                                                   b.eq    LBB1_10
        sdiv    w8, w0, w1                        LBB1_3:
        msub    w9, w8, w1, w0                            sdiv    w0, w8, w1
        eor     w10, w1, w0                               msub    w8, w0, w1, w8
        asr     w10, w10, rust-lang#31                             tbz     w1, rust-lang#31, LBB1_5
        cmp     w9, #0                                    cmp     w8, #0
        csel    w9, wzr, w10, eq                          b.gt    LBB1_7
        add     w0, w9, w8                        LBB1_5:
        ldp     x29, x30, [sp], rust-lang#16                       cmp     w1, #1
        ret                                               b.lt    LBB1_8
LBB0_4:                                                   tbz     w8, rust-lang#31, LBB1_8
        adrp    x0, l___unnamed_1@PAGE            LBB1_7:
        add     x0, x0, l___unnamed_1@PAGEOFF             sub     w0, w0, #1
        bl      panic...                          LBB1_8:
LBB0_5:                                                   ldp     x29, x30, [sp], rust-lang#16
        adrp    x0, l___unnamed_1@PAGE                    ret
        add     x0, x0, l___unnamed_1@PAGEOFF     LBB1_9:
        bl      panic...                                  adrp    x0, l___unnamed_2@PAGE
                                                          add     x0, x0, l___unnamed_2@PAGEOFF
                                                          bl      panic...
                                                  LBB1_10:
                                                          adrp    x0, l___unnamed_2@PAGE
                                                          add     x0, x0, l___unnamed_2@PAGEOFF
                                                          bl      panic...
```
lnicola pushed a commit to lnicola/rust-analyzer that referenced this issue Sep 25, 2024
better implementation of signed div_floor/ceil

Tracking issue for signed `div_floor`/`div_ceil`: rust-lang/rust#88581.

This PR improves the implementation of those two functions by adding a better branchless algorithm. Side-by-side comparison of `i32::div_floor` on x86-64:

```asm
div_floor_new:                               div_floor_old:
        push    rax                                  push    rax
        test    esi, esi                             test    esi, esi
        je      .LBB0_3                              je      .LBB1_6
        mov     eax, esi                             mov     eax, esi
        not     eax                                  not     eax
        lea     ecx, [rdi - 2147483648]              lea     ecx, [rdi - 2147483648]
        or      ecx, eax                             or      ecx, eax
        je      .LBB0_2                              je      .LBB1_7
        mov     eax, edi                             mov     eax, edi
        cdq                                          cdq
        idiv    esi                                  idiv    esi
        xor     esi, edi                             test    edx, edx
        sar     esi, 31                              setg    cl
        test    edx, edx                             test    esi, esi
        cmove   esi, edx                             sets    dil
        add     eax, esi                             test    dil, cl
        pop     rcx                                  jne     .LBB1_4
        ret                                          test    edx, edx
.LBB0_3:                                             setns   cl
        lea     rdi, [rip + .L__unnamed_1]           test    esi, esi
        call    qword ptr [rip + panic...]          setle   dl
.LBB0_2:                                             or      dl, cl
        lea     rdi, [rip + .L__unnamed_1]           jne     .LBB1_5
        call    qword ptr [rip + panic...]   .LBB1_4:
                                                     dec     eax
                                             .LBB1_5:
                                                     pop     rcx
                                                     ret
                                             .LBB1_6:
                                                     lea     rdi, [rip + .L__unnamed_2]
                                                     call    qword ptr [rip + panic...]
                                             .LBB1_7:
                                                     lea     rdi, [rip + .L__unnamed_2]
                                                     call    qword ptr [rip + panic...]
```

And on Aarch64:

```asm
_div_floor_new:                                   _div_floor_old:
        stp     x29, x30, [sp, #-16]!                     stp     x29, x30, [sp, #-16]!
        mov     x29, sp                                   mov     x29, sp
        cbz     w1, LBB0_4                                cbz     w1, LBB1_9
        mov     w8, #-2147483648                          mov     x8, x0
        cmp     w0, w8                                    mov     w9, #-2147483648
        b.ne    LBB0_3                                    cmp     w0, w9
        cmn     w1, rust-lang#1                                    b.ne    LBB1_3
        b.eq    LBB0_5                                    cmn     w1, rust-lang#1
LBB0_3:                                                   b.eq    LBB1_10
        sdiv    w8, w0, w1                        LBB1_3:
        msub    w9, w8, w1, w0                            sdiv    w0, w8, w1
        eor     w10, w1, w0                               msub    w8, w0, w1, w8
        asr     w10, w10, rust-lang#31                             tbz     w1, rust-lang#31, LBB1_5
        cmp     w9, #0                                    cmp     w8, #0
        csel    w9, wzr, w10, eq                          b.gt    LBB1_7
        add     w0, w9, w8                        LBB1_5:
        ldp     x29, x30, [sp], rust-lang#16                       cmp     w1, rust-lang#1
        ret                                               b.lt    LBB1_8
LBB0_4:                                                   tbz     w8, rust-lang#31, LBB1_8
        adrp    x0, l___unnamed_1@PAGE            LBB1_7:
        add     x0, x0, l___unnamed_1@PAGEOFF             sub     w0, w0, rust-lang#1
        bl      panic...                          LBB1_8:
LBB0_5:                                                   ldp     x29, x30, [sp], rust-lang#16
        adrp    x0, l___unnamed_1@PAGE                    ret
        add     x0, x0, l___unnamed_1@PAGEOFF     LBB1_9:
        bl      panic...                                  adrp    x0, l___unnamed_2@PAGE
                                                          add     x0, x0, l___unnamed_2@PAGEOFF
                                                          bl      panic...
                                                  LBB1_10:
                                                          adrp    x0, l___unnamed_2@PAGE
                                                          add     x0, x0, l___unnamed_2@PAGEOFF
                                                          bl      panic...
```
@thaliaarchi
Copy link
Contributor

I am interested in this being fleshed out, so I surveyed the methods. The following division/remainder methods are not implemented. For ceiling and floored rounding, there is no rem_* analogues to div_* and none of the versions that control overflow and wrapping. Additionally, there is no Euclidean saturating division or any saturating remainders.

I maintain a document tracking rounding of division and modulo across languages, which may be a useful reference.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C-tracking-issue Category: An issue tracking the progress of sth. like the implementation of an RFC disposition-merge This issue / PR is in PFCP or FCP with a disposition to merge it. finished-final-comment-period The final comment period is finished for this PR / Issue. T-libs-api Relevant to the library API team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests