Vec.reserve() prevents optimizations, libstd can't hint

Growth of Vec is rightfully handled in an uninlined #[cold] function. Unfortunately, this makes Vec's growth opaque to the optimizer, and the optimizer does not "know" what is the new len and capacity of the Vec after reserve.

This code should reserve capacity once:


but actually tries to reserve capacity twice, because the optimizer doesn't know what (try_)reserve does, so it keeps redundant second reserve in extend_from_slice.

It is fixable by adding a hint:

pub fn reserve(v: &mut Vec<u8>, additional: usize) {
    unsafe {
        core::intrinsics::assume(additional <= v.capacity().wrapping_sub(v.len()));

but this seems to work only in user code. When I put such hints in the liballoc, they seem to have no effect at all. I've even tried #[inline(always)] in std, but nope.

Any idea how to fix that? I presume that liballoc is special, and perhaps the hints don't survive in it?


Does it have to do with the fact that std is precompiled? Does using build-std make it work?

I've tried cargo +stage2 -Zbuild-std asm, and it didn't help.

1 Like

Odd that it's not working at all. Similar things appear to work in

edit: I missed that this PR hasn't been merged yet. Cherry-picked, it does work indeed.

1 Like

Somewhat relevant issue: Add unreachable hints for length getters? · Issue #106737 · rust-lang/rust · GitHub

One difference between Hint optimizer about reserved capacity by kornelski · Pull Request #116568 · rust-lang/rust · GitHub (from the OP) and (the one linked to by scottmcm) is that the former is in RawVec but the latter is in Vec.

Does copying the hints to Vec change anything?

No, it doesn't help. I've tried it in Vec methods too, and with #[inline] and #[inline(always)] as well.