Skip to content

Commit ba16851

Browse files
committed
Auto merge of rust-lang#121300 - c410-f3r:perf-try, r=<try>
[Experiment] Eliminate possible `Vec::push` branches Related to rust-lang#105156. Requesting a perf run. ```rust pub fn push(v: &mut Vec<u8>) { let _ = v.reserve(4); v.push(1); v.push(2); v.push(3); v.push(4); } ``` AFAICT, the codegen backend should infer the infallibility of these `push`s but unfortunately with LLVM 18 we still have unnecessary `reserve_for_push` branches. For the sake of curiosity, `assert_unchecked` was included in `push` to see any potential impact of such change. Take a look at the generated assembly at https://godbolt.org/z/b5jjPhsf8. AFAICT (again), the assumption of more available capacity for each `push` is not valid for all situations.
2 parents 43d3470 + e64d4ba commit ba16851

File tree

2 files changed

+21
-0
lines changed

2 files changed

+21
-0
lines changed

library/alloc/src/vec/mod.rs

+5
Original file line numberDiff line numberDiff line change
@@ -905,10 +905,14 @@ impl<T, A: Allocator> Vec<T, A> {
905905
/// vec.reserve(10);
906906
/// assert!(vec.capacity() >= 11);
907907
/// ```
908+
#[inline(always)]
908909
#[cfg(not(no_global_oom_handling))]
909910
#[stable(feature = "rust1", since = "1.0.0")]
910911
pub fn reserve(&mut self, additional: usize) {
911912
self.buf.reserve(self.len, additional);
913+
unsafe {
914+
core::hint::assert_unchecked(self.len().unchecked_add(additional) <= self.capacity());
915+
}
912916
}
913917

914918
/// Reserves the minimum capacity for at least `additional` more elements to
@@ -1925,6 +1929,7 @@ impl<T, A: Allocator> Vec<T, A> {
19251929
let end = self.as_mut_ptr().add(self.len);
19261930
ptr::write(end, value);
19271931
self.len += 1;
1932+
core::hint::assert_unchecked(self.len() <= self.capacity());
19281933
}
19291934
}
19301935

tests/codegen/reserve_local_push.rs

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// compile-flags: -O
2+
3+
#![crate_type = "lib"]
4+
5+
#[no_mangle]
6+
pub fn push(v: &mut Vec<u8>) {
7+
let _ = v.reserve(4);
8+
// CHECK-NOT: call {{.*}}reserve_for_push
9+
v.push(1);
10+
// CHECK-NOT: call {{.*}}reserve_for_push
11+
v.push(2);
12+
// CHECK-NOT: call {{.*}}reserve_for_push
13+
v.push(3);
14+
// CHECK-NOT: call {{.*}}reserve_for_push
15+
v.push(4);
16+
}

0 commit comments

Comments
 (0)