Skip to content

Failure to optimize udiv/urem when non-constant divisor is known power of two #115767

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

Closed
Kmeakin opened this issue Nov 11, 2024 · 1 comment · Fixed by #121386
Closed

Failure to optimize udiv/urem when non-constant divisor is known power of two #115767

Kmeakin opened this issue Nov 11, 2024 · 1 comment · Fixed by #121386

Comments

@Kmeakin
Copy link
Contributor

Kmeakin commented Nov 11, 2024

Strength reduction can be performed on udiv/urem if the divisor is known to be a power of two, due to dominating condition or assume:

Compiler explorer: https://godbolt.org/z/4ncnjsPTM
Alive proof: https://alive2.llvm.org/ce/z/3FJYeg

#![feature(core_intrinsics)]

use std::hint::assert_unchecked as assume;
use std::intrinsics::unchecked_div;
use std::intrinsics::unchecked_rem;

#[no_mangle]
pub fn src_udiv_if(x: u32, y: u32) -> u32 {
    if y.is_power_of_two() {
        unsafe { unchecked_div(x, y) }
    } else {
        0
    }
}

#[no_mangle]
pub fn tgt_udiv_if(x: u32, y: u32) -> u32 {
    if y.is_power_of_two() {
        x >> y.trailing_zeros()
    } else {
        0
    }
}

#[no_mangle]
pub fn src_udiv_assume(x: u32, y: u32) -> u32 {
    unsafe {
        assume(y.is_power_of_two());
        unchecked_div(x, y)
    }
}

#[no_mangle]
pub fn tgt_udiv_assume(x: u32, y: u32) -> u32 {
    unsafe {
        assume(y.is_power_of_two());
        x >> y.trailing_zeros()
    }
}

#[no_mangle]
pub fn src_urem_if(x: u32, y: u32) -> u32 {
    if y.is_power_of_two() {
        unsafe { unchecked_rem(x, y) }
    } else {
        0
    }
}

#[no_mangle]
pub fn tgt_urem_if(x: u32, y: u32) -> u32 {
    if y.is_power_of_two() {
        x & (y - 1)
    } else {
        0
    }
}

#[no_mangle]
pub fn src_urem_assume(x: u32, y: u32) -> u32 {
    unsafe {
        assume(y.is_power_of_two());
        unchecked_rem(x, y)
    }
}

#[no_mangle]
pub fn tgt_urem_assume(x: u32, y: u32) -> u32 {
    unsafe {
        assume(y.is_power_of_two());
        x & (y - 1)
    }
}
@veera-sivarajan
Copy link
Contributor

urem is being reduced to bitwise operations since #107994.

I'll fix udiv.

dtcxzyw pushed a commit that referenced this issue Jan 11, 2025

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
#121386)

Fixes #115767

This PR folds `X udiv Y` to `X lshr cttz(Y)` if Y is a power of two
since bitwise operations are faster than division.

Proof: https://alive2.llvm.org/ce/z/qHmLta
BaiXilin pushed a commit to BaiXilin/llvm-fix-vnni-instr-types that referenced this issue Jan 12, 2025
llvm#121386)

Fixes llvm#115767

This PR folds `X udiv Y` to `X lshr cttz(Y)` if Y is a power of two
since bitwise operations are faster than division.

Proof: https://alive2.llvm.org/ce/z/qHmLta
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants