Skip to content

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

Closed
@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

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions