Skip to content

vec::IntoIter<[T]>::next generates unnecessary null checking #106368

@AnsonYeung

Description

@AnsonYeung

For the following code, it seems the compiler was unable to optimize away the loop for the first 2 functions.

pub fn vec(foo: Vec<&[i32]>) -> usize {
    into_iter_last(foo.into_iter())
}

pub fn vec2(foo: Vec<&[i32]>) -> usize {
    into_iter_last(foo.into_iter().map(|s| *&s))
}

pub fn vec3(foo: Vec<&[i32]>) -> usize {
    into_iter_last(foo.iter().map(|s| *s))
}

pub fn slice(foo: &[&[i32]]) -> usize {
    into_iter_last(foo.into_iter().map(|s| *s))
}

pub fn into_iter_last<'a>(mut foo: impl Iterator<Item = &'a [i32]>) -> usize {
    let mut res = 0;
    while let Some(slice) = foo.next() {
        res = slice.len();
    }
    res
}

This seems to be only happening for Vec and not slice. Seems like the compiler forgets that slice ptr cannot be null and unable to optimize away the loop.

https://rust.godbolt.org/z/7EvqWE7vv

example::vec:
        push    rbx
        mov     rax, rdi
        mov     rsi, qword ptr [rdi]
        mov     rdi, qword ptr [rdi + 8]
        mov     rax, qword ptr [rax + 16]
        test    rax, rax
        je      .LBB0_6
        cmp     qword ptr [rdi], 0
        je      .LBB0_6
        shl     rax, 4
        mov     edx, 16
.LBB0_3:
        mov     rcx, rdx
        cmp     rax, rdx
        je      .LBB0_5
        lea     rdx, [rcx + 16]
        cmp     qword ptr [rdi + rcx], 0  ; unnecessary null check
        jne     .LBB0_3
.LBB0_5:
        mov     rbx, qword ptr [rdi + rcx - 8]
        test    rsi, rsi
        jne     .LBB0_7
        jmp     .LBB0_8
.LBB0_6:
        xor     ebx, ebx
        test    rsi, rsi
        je      .LBB0_8
.LBB0_7:
        shl     rsi, 4
        mov     edx, 8
        call    qword ptr [rip + __rust_dealloc@GOTPCREL]
.LBB0_8:
        mov     rax, rbx
        pop     rbx
        ret

example::vec2:
        push    rbx
        mov     rax, rdi
        mov     rsi, qword ptr [rdi]
        mov     rdi, qword ptr [rdi + 8]
        mov     rax, qword ptr [rax + 16]
        test    rax, rax
        je      .LBB1_6
        cmp     qword ptr [rdi], 0  ; unnecessary null check
        je      .LBB1_6
        shl     rax, 4
        mov     edx, 16
.LBB1_3:
        mov     rcx, rdx
        cmp     rax, rdx
        je      .LBB1_5
        lea     rdx, [rcx + 16]
        cmp     qword ptr [rdi + rcx], 0
        jne     .LBB1_3
.LBB1_5:
        mov     rbx, qword ptr [rdi + rcx - 8]
        test    rsi, rsi
        jne     .LBB1_7
        jmp     .LBB1_8
.LBB1_6:
        xor     ebx, ebx
        test    rsi, rsi
        je      .LBB1_8
.LBB1_7:
        shl     rsi, 4
        mov     edx, 8
        call    qword ptr [rip + __rust_dealloc@GOTPCREL]
.LBB1_8:
        mov     rax, rbx
        pop     rbx
        ret

example::vec3:
        push    rbx
        mov     rax, rdi
        mov     rdi, qword ptr [rdi + 8]
        mov     rcx, qword ptr [rax + 16]
        test    rcx, rcx
        je      .LBB2_1
        shl     rcx, 4
        mov     rbx, qword ptr [rcx + rdi - 8]
        mov     rsi, qword ptr [rax]
        test    rsi, rsi
        je      .LBB2_5
.LBB2_4:
        shl     rsi, 4
        mov     edx, 8
        call    qword ptr [rip + __rust_dealloc@GOTPCREL]
.LBB2_5:
        mov     rax, rbx
        pop     rbx
        ret
.LBB2_1:
        xor     ebx, ebx
        mov     rsi, qword ptr [rax]
        test    rsi, rsi
        jne     .LBB2_4
        jmp     .LBB2_5

example::slice:
        test    rsi, rsi
        je      .LBB3_1
        shl     rsi, 4
        mov     rax, qword ptr [rsi + rdi - 8]
        ret
.LBB3_1:
        xor     eax, eax
        ret

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions