Repository: rust
Issue: Missed optimization: states guarenteed after first iteration of loop
Labels: T-compiler,F-let_chains,C-optimization

Take this example:
```rust
#![feature(let_chains)]

#[no_mangle]
pub fn kinda_sort_merge(
    query_ids: &[u32],
    value_ids: &[u32],
) -> u32
{
    let mut result = 0;
    let mut v_iter = value_ids.iter();
    let mut current = v_iter.next(); // May be None
    for &q_id in query_ids.iter() {
        while let Some(&v_id) = current && v_id < q_id {
            current = v_iter.next();
        }
        match current {
            Some(&v_id) => {result += v_id * q_id;}
            None => {break;}
        }
        // After the first iteration, Current is guaranteed to be Some at the start of every iteration.
    }
    result
}
```

You'd expect in the hot loop of the resulting assembly to have 2 possible jumps to return: one for the end of `query_ids`, and one for the end of `value_ids`. However, there are 3 of them:
```asm
kinda_sort_merge:
        test    rsi, rsi
        je      .LBB0_8                       ; Check for query_ids.len() != 0
        lea     r8, [rdx + 4*rcx]
        lea     rsi, [rdi + 4*rsi]
        xor     eax, eax
        test    rcx, rcx
        setne   al
        lea     r9, [rdx + 4*rax]
        cmove   rdx, rcx
        xor     ecx, ecx
.LBB0_2:                                      ; Hot loop
        test    rdx, rdx
        je      .LBB0_10                      ; 1, check for v_iter before while loop
        mov     r10d, dword ptr [rdi]
        add     rdi, 4
        mov     rax, r9
.LBB0_4:
        mov     r9, rax
        mov     eax, dword ptr [rdx]
        cmp     eax, r10d
        jae     .LBB0_6
        lea     rax, [r9 + 4]
        mov     rdx, r9
        cmp     r9, r8
        jne     .LBB0_4
        jmp     .LBB0_10                      ; 2, check for v_iter during while loop
.LBB0_6:
        imul    eax, r10d
        add     eax, ecx
        mov     ecx, eax
        cmp     rdi, rsi
        jne     .LBB0_2
        jmp     .LBB0_9                       ; 3, check for query_ids
.LBB0_10:
        mov     eax, ecx
        ret
.LBB0_8:
        xor     eax, eax
.LBB0_9:
        ret
```

By adding `assert_unchecked()`:
```rust
#![feature(let_chains)]
use std::hint::assert_unchecked;

#[no_mangle]
pub fn kinda_sort_merge(
    query_ids: &[u32],
    value_ids: &[u32],
) -> u32
{
    let mut result = 0;
    let mut v_iter = value_ids.iter();
    let mut current = v_iter.next();
    let b = current.is_some();
    for &q_id in query_ids.iter() {
        if b {unsafe {assert_unchecked(current.is_some())}}
        while let Some(&v_id) = current && v_id < q_id {
            current = v_iter.next();
        }
        if !b {unsafe {assert_unchecked(current.is_none())}}
        match current {
            Some(&v_id) => {result += v_id * q_id;}
            None => {break;}
        }
    }
    result
}
```

The assembly quality improves:
```asm
kinda_sort_merge:
        test    rcx, rcx
        sete    r8b
        test    rsi, rsi
        sete    r9b
        xor     eax, eax
        or      r9b, r8b
        jne     .LBB0_7                         ; Check for both's len different from 0
        lea     rcx, [rdx + 4*rcx]
        lea     rsi, [rdi + 4*rsi]
        lea     r9, [rdx + 4]
        xor     r8d, r8d
.LBB0_2:                                        ; Hot loop
        mov     r10d, dword ptr [rdi]
        add     rdi, 4
        mov     rax, r9
.LBB0_3:
        mov     r9, rax
        mov     eax, dword ptr [rdx]
        cmp     eax, r10d
        jae     .LBB0_4
        lea     rax, [r9 + 4]
        mov     rdx, r9
        cmp     r9, rcx
        jne     .LBB0_3
        jmp     .LBB0_6                         ; 1, check for v_iter during while loop
.LBB0_4:
        imul    eax, r10d
        add     eax, r8d
        mov     r8d, eax
        cmp     rdi, rsi
        jne     .LBB0_2
        jmp     .LBB0_7                         ; 2, check for v_iter
.LBB0_6:
        mov     eax, r8d
.LBB0_7:
        ret
```

[Godbolt](https://godbolt.org/#g:!((g:!((g:!((h:codeEditor,i:(filename:'1',fontScale:14,fontUsePx:'0',j:1,lang:rust,selection:(endColumn:11,endLineNumber:25,positionColumn:11,positionLineNumber:25,selectionStartColumn:11,selectionStartLineNumber:25,startColumn:11,startLineNumber:25),source:'%23!!%5Bfeature(let_chains)%5D%0Ause+std::hint::assert_unchecked%3B%0A%0A%23%5Bno_mangle%5D%0Apub+fn+kinda_sort_merge(%0A++++query_ids:+%26%5Bu32%5D,%0A++++value_ids:+%26%5Bu32%5D,%0A)+-%3E+u32%0A%7B%0A++++let+mut+result+%3D+0%3B%0A++++let+mut+v_iter+%3D+value_ids.iter()%3B%0A++++let+mut+current+%3D+v_iter.next()%3B%0A++++let+b+%3D+current.is_some()%3B%0A++++for+%26q_id+in+query_ids.iter()+%7B%0A++++++++if+b+%7Bunsafe+%7Bassert_unchecked(current.is_some())%7D%7D%0A++++++++while+let+Some(%26v_id)+%3D+current+%26%26+v_id+%3C+q_id+%7B%0A++++++++++++current+%3D+v_iter.next()%3B%0A++++++++%7D%0A++++++++if+!!b+%7Bunsafe+%7Bassert_unchecked(current.is_none())%7D%7D%0A++++++++match+current+%7B%0A++++++++++++Some(%26v_id)+%3D%3E+%7Bresult+%2B%3D+v_id+*+q_id%3B%7D%0A++++++++++++None+%3D%3E+%7Bbreak%3B%7D%0A++++++++%7D%0A++++%7D%0A++++result%0A%7D'),l:'5',n:'0',o:'Rust+source+%231',t:'0')),k:56.083086053412465,l:'4',n:'0',o:'',s:0,t:'0'),(g:!((h:executor,i:(argsPanelShown:'1',compilationPanelShown:'0',compiler:nightly,compilerName:'',compilerOutShown:'0',execArgs:'',execStdin:'',fontScale:14,fontUsePx:'0',j:1,lang:rust,libs:!(),options:'',overrides:!((name:edition,value:'2021')),runtimeTools:!(),source:1,stdinPanelShown:'1',wrap:'1'),l:'5',n:'0',o:'Executor+rustc+nightly+(Rust,+Editor+%231)',t:'0'),(h:compiler,i:(compiler:nightly,filters:(b:'0',binary:'1',binaryObject:'1',commentOnly:'0',debugCalls:'1',demangle:'0',directives:'0',execute:'1',intel:'0',libraryCode:'0',trim:'1',verboseDemangling:'0'),flagsViewOpen:'1',fontScale:14,fontUsePx:'0',j:1,lang:rust,libs:!(),options:'-C+opt-level%3D3',overrides:!((name:edition,value:'2021')),selection:(endColumn:12,endLineNumber:37,positionColumn:1,positionLineNumber:1,selectionStartColumn:12,selectionStartLineNumber:37,startColumn:1,startLineNumber:1),source:1),l:'5',n:'0',o:'+rustc+nightly+(Editor+%231)',t:'0')),k:43.916913946587535,l:'4',n:'0',o:'',s:1,t:'0')),l:'2',n:'0',o:'',t:'0')),version:4)