rust-lang / rust-lang/rust

Codegen struggles to infer information about a value computed before branching on related info

Open
#155,809 10 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

A-codegen A-LLVM C-optimization I-slow needs-triage T-compiler
Dominant language
Rust
Stars
119k
Forks
16.1k
PR merge metrics
PR metrics pending

Description

Explanation:

/// basically what the function looks like in core
fn strict_sub(x: u128, y: u128) -> u128 {
      let (diff, over) = x.overflowing_sub(y);
      if over { panic!() } else { diff }
}
/// this is better for some reason
fn strict_sub_1liner(x: u128, y: u128) -> u128 {
      if x <= y { panic!() } else { x - y }
}

/// Performs the Lucas Lehmer Test to see if `2^exp - 1` is prime.
/// Panics if `2^exp` does not fit in a u64.
pub fn lucas_lehmer_u64(exp: u8) -> bool {
    let n64: u64 = 1u64.strict_shl(exp as u32) - 1;
    let n: u128 = n64 as u128;
    
    let mut k: u128 = 4;
    
    // swapping out `strict_sub` here for `strict_sub_1line` allows the compiler to
    // figure out that the `strict_add` later won't panic.
    // For context, that wont panic because `k` is always less then `n` at the end and
    // `n` can fit in a `u64` so if you square it it won't be too large to then add a `n_m2`
    // if that also fits in a `u64` (basically the idea behind the `carrying_mul`  and 
    // `carrying_mul_add` function). 
    // If `n_m2` were to underflow, it won't fit anymore and the `strict_add` can overflow.
    let n_m2 = strict_sub(n, 2);
    
    let mut i = 2;
    
    while i < exp {
        k = (k*k).strict_add(n_m2);
        unsafe {
            k = (k & n).unchecked_add(k >> exp);
            k = (k & n).unchecked_add(k >> exp);
        }
        k = core::hint::select_unpredictable(k == n, 0, k);
        // above 3 statements perform `k mod n` so `k` is less then `n`
        unsafe { core::hint::assert_unchecked(k < n) }
        i += 1;
    }
    k == 0
}

godbolt link: https://godbolt.org/z/h4Gcn4Pvz

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the Godbolt reproduction and compare code generation for strict_sub and strict_sub_1liner in the Lucas–Lehmer example. Trace how the compiler reasons about the overflowing_sub result before the branch and how that affects the later strict_add. Done means the differing inference or code-generation behavior is understood and the issue has a verified compiler-side resolution.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
compilers
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.