Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

checked_div happy path #73731

Closed
leonardo-m opened this issue Jun 25, 2020 · 8 comments · Fixed by #73938
Closed

checked_div happy path #73731

leonardo-m opened this issue Jun 25, 2020 · 8 comments · Fixed by #73938
Assignees
Labels
A-codegen Area: Code generation T-libs Relevant to the library team, which will review and decide on the PR/issue.

Comments

@leonardo-m
Copy link

leonardo-m commented Jun 25, 2020

This is a kind of enhancement suggestion. Given this function:

pub fn foo7(n: u32, v: u32) -> Option<u32> {
    n.checked_div(v + 1)
}

Compiled wih rustc 1.46.0-nightly (67100f6 2020-06-24) with good optimization flags gives:

example::foo7:
	inc     esi
	jne     .LBB0_3
	xor     eax, eax
	ret
.LBB0_3:
	mov     eax, edi
	xor     edx, edx
	div     esi
	mov     edx, eax
	mov     eax, 1
	ret

But I think the happy path should be with the denominator != 0 (that hopefully is the most common case), instead of the case with a division by zero.

So I've done few more experiments:

#![feature(core_intrinsics)]
use std::intrinsics::{unchecked_div, unlikely, likely};

pub fn checked_div1(this: u32, rhs: u32) -> Option<u32> {
    match rhs {
        0 => None,
        rhs => Some(unsafe { unchecked_div(this, rhs) }),
    }
}

pub fn foo1(n: u32, v: u32) -> Option<u32> {
    checked_div1(n, v + 1)
}

pub fn checked_div2(this: u32, rhs: u32) -> Option<u32> {
    if rhs != 0 {
        Some(unsafe { unchecked_div(this, rhs) })
    } else {
        None         
    }
}

pub fn foo2(n: u32, v: u32) -> Option<u32> {
    checked_div2(n, v + 1)
}

pub fn checked_div3(this: u32, rhs: u32) -> Option<u32> {
    if unlikely(rhs == 0) {
        None
    } else {
        Some(unsafe { unchecked_div(this, rhs) })
    }
}

pub fn foo3(n: u32, v: u32) -> Option<u32> {
    checked_div3(n, v + 1)
}

pub fn foo4(n: u32, v: u32) -> Option<u32> {
    if likely(v + 1 != 0) {
        Some(unsafe { unchecked_div(n, v + 1) })
    } else {
        None        
    }
}

The asm:

example::checked_div1:
	test    esi, esi
	je      .LBB0_1
	mov     eax, edi
	xor     edx, edx
	div     esi
	mov     edx, eax
	mov     eax, 1
	ret
.LBB0_1:
	xor     eax, eax
	ret

example::foo1:
	inc     esi
	jne     .LBB1_2
	xor     eax, eax
	ret
.LBB1_2:
	mov     eax, edi
	xor     edx, edx
	div     esi
	mov     edx, eax
	mov     eax, 1
	ret

This issue has been assigned to @nbdd0121 via this comment.

@nagisa nagisa added the A-codegen Area: Code generation label Jun 25, 2020
@nagisa
Copy link
Member

nagisa commented Jun 25, 2020

Ideally/most cleanly solved with some branch weight annotation that we don’t have implemented yet.

I wouldn’t rely much on re-arranging Rust code much as that can break again on a whim.

@leonardo-m
Copy link
Author

Isn't std::intrinsics::likely a branch weight annotation? Isn't it working in Rust?

@nagisa
Copy link
Member

nagisa commented Jun 25, 2020

Oh I guess that ended up being added, I skimmed past that part in your report. Yeah in that case we should just go with one of the if unlikely options.

@nbdd0121
Copy link
Contributor

I had a try, but it cannot yet be implemented because likely/unlikely are not yet const intrinsics.

@nbdd0121
Copy link
Contributor

Okay I have a working version here. However this would be blocked until likely and unlikely is made const.

@rustbot claim

@rustbot rustbot self-assigned this Jun 26, 2020
@LeSeulArtichaut LeSeulArtichaut added S-blocked Status: Blocked on something else such as an RFC or other implementation work. T-libs Relevant to the library team, which will review and decide on the PR/issue. labels Jun 26, 2020
@nagisa
Copy link
Member

nagisa commented Jun 26, 2020

@oli-obk @RalfJung any reason we cannot or should not make the likely/unlikely intrinsic const?

@RalfJung
Copy link
Member

RalfJung commented Jun 26, 2020

None that I can think of. But this requires T-lang approval (through FCP I presume) as it is an intrinsic. Better make it a separate PR.

@nbdd0121
Copy link
Contributor

nbdd0121 commented Jul 1, 2020

@rustbot modify labels: -S-blocked

@rustbot rustbot removed the S-blocked Status: Blocked on something else such as an RFC or other implementation work. label Jul 1, 2020
@bors bors closed this as completed in 4f536f2 Jul 2, 2020
# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
A-codegen Area: Code generation T-libs Relevant to the library team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants