Skip to content

Vec::reserve(n) followed by n calls to push should only check capacity once #105156

Open
@jhorstmann

Description

@jhorstmann

I tried this code in compiler explorer (https://rust.godbolt.org/z/W35vT4osM):

pub fn push1(v: &mut Vec<u32>, x: u32) {
    v.reserve(1);
    v.push(x);
}

pub fn push2(v: &mut Vec<u32>, x: u32) {
    v.reserve(2);
    v.push(x);
    v.push(x);
}

I expected the generated assembly to only check the capacity once, and reallocate if needed, and then write the value. Instead, for each push there is another check of remaining capacity and potential call to reserve_for_push.

Adding explicit assume calls leads to much shorter code with only a single call to do_reserve_and_handle.

pub fn push2_assume(v: &mut Vec<u32>, x: u32) {
    v.reserve(2);

    unsafe {
        core::intrinsics::assume(v.len() < v.capacity());
    }
    v.push(x);

    unsafe {
        core::intrinsics::assume(v.len() < v.capacity());
    }
    v.push(x);
}

This seems similar to #82801 but that issue seems specific to the initial vector capacity and code for that case looks ok now.

Meta

rustc --version --verbose:

rustc 1.67.0-nightly (e0098a5cc 2022-11-29)
binary: rustc
commit-hash: e0098a5cc3a87d857e597af824d0ce1ed1ad85e0
commit-date: 2022-11-29
host: x86_64-unknown-linux-gnu
release: 1.67.0-nightly
LLVM version: 15.0.4
Compiler returned: 0

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-codegenArea: Code generationC-optimizationCategory: An issue highlighting optimization opportunities or PRs implementing suchI-slowIssue: Problems and improvements with respect to performance of generated code.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions