Why does the compiler recalculate a value that was already available in another register?

Viewed 101

I’m studying machine code produced by the Rust compiler. Here is a simple function that calculates the sum of all elements in a slice. (In Rust, a slice is essentially an array whose length is generally only known at runtime. It resides in a contiguous region of memory and is described by a pointer to the first element and the number of elements.)

fn sum_imperative(slice: &[i64]) -> i64 {
    let mut sum = 0;
    for n in slice {
        sum += n;
    }
    sum
}

With SSE disabled and optimizations turned on, rustc 1.46.0 produces code that starts like this:

example::sum_imperative:
        test    rsi, rsi
        je      .LBB0_1
        lea     rax, [8*rsi - 8]
        mov     rdx, rax
        shr     rdx, 3
        add     rdx, 1

Here, the number of elements N in the slice is in rsi. If my understanding is correct, the code first calculates 8N−8 and stores that in rax. Then it uses that result to calculate (8N−8)/8+1 and stores that in rdx. Assuming there is no overflow, the rdx result should always be equal to the original value of N that is still available in rsi.

Why did the compiler recalculate the value of N rather than use one that was already available in rsi?

0 Answers
Related