Skip to content

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

@Kmeakin

Description

@Kmeakin

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)
    }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions