Unable to optimize bounds checks

In this case it's not true. They are equivalent. The assert can't possibly fire. The bounds checks can't possibly fail. The compiler is just not smart enough to figure it out.

We know that len > 0 (because of the is_empty() check), therefore len - 1 doesn't overflow. i < len - 1. Therefore len - i > 1 and the slice can't be empty.

Of course if we ignore surrounding context they might not be equivalent, which is probably what you meant, but that's a different story. Many optimizations have to look at some information from the context.

I'm a bit disappointed with the compiler failing at analyzing such simple inequalities. This sort of never failing bounds checks are pretty common, it would help optimize a lot of code if the compiler could get rid of them.

1 Like

Even worse, the compiler is unable to remove bound checks even for a function like this:

pub fn foo(buf: &mut [u32]) {
    if buf.is_empty() {
        return;
    }
    for i in 0..buf.len() - 1 {
        &buf[..i];
    }
}

Interestingly enough, no panics with &buf[i] instead of slicing.

Of course, the concrete code OP posted is written correctly so the assert can't fire. But in general, what I wrote is true: an upfront assertion doesn't necessarily behave the same as a failing bounds check in the middle of the loop. It is also true that the very obvious structure of the assertion is easier for the compiler to optimize.

Here's a previous thread with some other examples, if you'd like:

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.