Repository: rust
Issue: Missed optimization: loop with increasing index doesn't elide bounds check
Labels: I-slow,C-enhancement,T-compiler,C-optimization

I tried this code and many variations of it and I found out this doesn't elide the bounds check on `&buf[i..]`.

```rust
pub fn problematic(buf: &[u8]) -> &[u8] {
    let mut i = 0;
    for b in buf {
        if *b == 0x00 {
            return &buf[i..];
        }

        i += 1;
    }

    &[]
}
```

<details>
<summary>Assembly Output</summary>

```assembly
example::problematic:
        pushq   %rax
        leaq    .L__unnamed_1(%rip), %rax
        xorl    %edx, %edx
        testq   %rsi, %rsi
        je      .LBB0_6
        xorl    %ecx, %ecx
.LBB0_2:
        cmpb    $0, (%rdi,%rcx)
        je      .LBB0_4
        addq    $1, %rcx
        cmpq    %rcx, %rsi
        jne     .LBB0_2
.LBB0_6:
        popq    %rcx
        retq
.LBB0_4:
        cmpq    %rsi, %rcx
        ja      .LBB0_7
        subq    %rcx, %rsi
        addq    %rcx, %rdi
        movq    %rsi, %rdx
        movq    %rdi, %rax
        popq    %rcx
        retq
.LBB0_7:
        leaq    .L__unnamed_2(%rip), %rdx
        movq    %rcx, %rdi
        callq   *core::slice::slice_index_order_fail@GOTPCREL(%rip)
        ud2

.L__unnamed_3:
        .ascii  "./example.rs"

.L__unnamed_2:
        .quad   .L__unnamed_3
        .asciz  "\f\000\000\000\000\000\000\000\005\000\000\000\025\000\000"

.L__unnamed_1:
```
</details>

---

Manually checking that `i` is ok elides the bounds check and ends up being optimized away!?

```rust
pub fn optimized(buf: &[u8]) -> &[u8] {
    let mut i = 0;
    for b in buf {
        // this gets optimized away?
        if i >= buf.len() { break; }

        if *b == 0x00 {
            return &buf[i..];
        }

        i += 1;
    }

    &[]
}
```

<details>
<summary>Assembly Output</summary>

```assembly
example::optimized:
        leaq    .L__unnamed_1(%rip), %rax
        testq   %rsi, %rsi
        je      .LBB0_5
        movq    %rsi, %rdx
.LBB0_2:
        cmpb    $0, (%rdi)
        je      .LBB0_3
        addq    $1, %rdi
        addq    $-1, %rdx
        jne     .LBB0_2
.LBB0_5:
        xorl    %edx, %edx
        retq
.LBB0_3:
        movq    %rdi, %rax
        retq

.L__unnamed_1:
```
</details>

---

This third example generates the same assembly as the second one, so I think it's really optimizing away the manual check on the second example?

```rust
pub fn optimized_unsafe(buf: &[u8]) -> &[u8] {
    let mut i = 0;
    for b in buf {
        if *b == 0x00 {
            return unsafe { buf.get_unchecked(i..) };
        }

        i += 1;
    }

    &[]
}
```

<details>
<summary>Assembly Output</summary>

```assembly
example::optimized_unsafe:
        leaq    .L__unnamed_1(%rip), %rax
        testq   %rsi, %rsi
        je      .LBB0_5
        movq    %rsi, %rdx
.LBB0_2:
        cmpb    $0, (%rdi)
        je      .LBB0_3
        addq    $1, %rdi
        addq    $-1, %rdx
        jne     .LBB0_2
.LBB0_5:
        xorl    %edx, %edx
        retq
.LBB0_3:
        movq    %rdi, %rax
        retq

.L__unnamed_1:
```
</details>

---

Possibly related: #74186