Eliminating redundant bounds checks on read+write mutable slices

I have a task that requires reading and writing to the same slice at different locations, and I can't convince Rust/LLVM to eliminate bounds checks in this case.

pub fn why_u_no_optimze(inout: &mut [u8], len: usize, offset: usize) {
    if inout.len() < len || inout.len() < offset || offset >= len || len >= u32::MAX as usize || offset > 8 {
        return;
    }
    for i in offset..len {
        inout[i] = inout[i-offset] + 1;
        //inout[i] = unsafe { *inout.get_unchecked(i-offset) } + 1;
    }
}

Using unsafe of course can work around the problem. But it's weird how stubborn LLVM is here.

changing [i-offset] to [i] eliminates bounds checks. But as far as I can tell, any arithmetic on the offset, even checked or saturating, ruins it.

And sadly due to aliasing, I can't use separate slices (chunking them or copying generates worse code than I'd like).

What's going on here? Is there safe code that optimizes better?

How about this?

use core::cell::Cell;

pub fn why_u_no_optimze(inout: &mut [u8], len: usize, offset: usize) {
    let inout = Cell::from_mut(inout)
        .as_slice_of_cells();
    
    if inout.len() < len || inout.len() < offset || inout.len() < len-offset || offset >= len || len >= u32::MAX as usize || offset > 8 {
        return;
    }

    let out = &inout[..len - offset];
    let inp = &inout[offset..len];

    for i in 0..len-offset {
        out[i].set(inp[i].get() + 1);
    }
}
4 Likes

Brilliant, it works! I forgot Cell exists.

1 Like

For anyone who -- like me -- always forgets the magic incantations for this, I added it to the windows docs: https://doc.rust-lang.org/std/primitive.slice.html#method.windows

4 Likes

While trying to eliminate bound checks in a similar case I found that signed integers, i.e. isize instead of usize, have better correlation propagation. I still have it on my to do list to find the correct place to file an issue. Here a minimal example: Compiler Explorer

5 Likes

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.