Skip to content

incorrect code generation for i686 release build for 1.47 beta and nightly #76042

Closed
@tspiteri

Description

@tspiteri
/// ```rust
/// assert_eq!(fixed::i124f4_wrapping_mul(3 << 4, 2 << 4), 6 << 4);
/// ```
#[inline]
pub fn i124f4_wrapping_mul(lhs: i128, rhs: i128) -> i128 {
    let (ans, _) = mul_overflow(lhs, rhs, 4);
    ans
}

#[inline]
fn mul_overflow(lhs: i128, rhs: i128, frac_nbits: u32) -> (i128, bool) {
    let (lh, ll) = hi_lo(lhs);
    let (rh, rl) = hi_lo(rhs);
    let ll_rl = ll.wrapping_mul(rl);
    let lh_rl = lh.wrapping_mul(rl);
    let ll_rh = ll.wrapping_mul(rh);
    let lh_rh = lh.wrapping_mul(rh);

    let col01 = ll_rl as u128;
    let (col01_hi, col01_lo) = (col01 >> 64, col01 & !(!0 << 64));
    let partial_col12 = lh_rl + col01_hi as i128;
    let (col12, carry_col3) = carrying_add(partial_col12, ll_rh);
    let (col12_hi, col12_lo) = hi_lo(col12);
    let ans01 = shift_lo_up_unsigned(col12_lo) + col01_lo;
    let ans23 = lh_rh + col12_hi + shift_lo_up(carry_col3);
    let ret = combine_lo_then_shl(ans23, ans01, frac_nbits);
    println!(
        "combine_lo_then_shl({}, {}, {}) -> ({}, {})",
        ans23, ans01, frac_nbits, ret.0, ret.1
    );
    ret
}

#[inline]
fn hi_lo(this: i128) -> (i128, i128) {
    (this >> 64, this & !(!0 << 64))
}

#[inline]
fn combine_lo_then_shl(this: i128, lo: u128, shift: u32) -> (i128, bool) {
    if shift == 128 {
        (this, false)
    } else if shift == 0 {
        let ans = lo as i128;
        (ans, this != if ans < 0 { -1 } else { 0 })
    } else {
        let lo = (lo >> shift) as i128;
        let hi = this << (128 - shift);
        let ans = lo | hi;
        (ans, this >> shift != if ans < 0 { -1 } else { 0 })
    }
}

#[inline]
fn carrying_add(this: i128, rhs: i128) -> (i128, i128) {
    let (sum, overflow) = this.overflowing_add(rhs);
    let carry = if overflow {
        if sum < 0 {
            1
        } else {
            -1
        }
    } else {
        0
    };
    (sum, carry)
}

#[inline]
fn shift_lo_up(this: i128) -> i128 {
    debug_assert!(this >> 64 == 0);
    this << 64
}

#[inline]
fn shift_lo_up_unsigned(this: i128) -> u128 {
    debug_assert!(this >> 64 == 0);
    (this << 64) as u128
}

The test passes for 1.46.0 i686 stable release builds, for i686 beta/nightly debug builds, and for x86_64 beta/nightly release builds, but fails for i686 beta/nightly release builds.

CI logs from this code on GitLab:

https://gitlab.com/tspiteri/fixed/-/pipelines/183281142

Metadata

Metadata

Assignees

Labels

A-LLVMArea: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues.C-bugCategory: This is a bug.I-unsoundIssue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/SoundnessICEBreaker-Cleanup-CrewHelping to "clean up" bugs with minimal examples and bisectionsO-x86_32Target: x86 processors, 32 bit (like i686-*) (IA-32)P-mediumMedium priorityT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.regression-from-stable-to-betaPerformance or correctness regression from stable to beta.

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions