From f1ae5314bef94f1defe868cb5d78d15b5da31c8c Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Sun, 14 Apr 2024 11:15:00 -0400 Subject: [PATCH] Avoid reloading Vec::len across grow_one in push This saves an extra load from memory. --- library/alloc/src/vec/mod.rs | 8 +++++--- tests/codegen/vec-len-invariant.rs | 16 ++++++++++++++++ 2 files changed, 21 insertions(+), 3 deletions(-) create mode 100644 tests/codegen/vec-len-invariant.rs diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 1930be65bfb..b2e22d8715a 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -1991,15 +1991,17 @@ impl Vec { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_confusables("push_back", "put", "append")] pub fn push(&mut self, value: T) { + // Inform codegen that the length does not change across grow_one(). + let len = self.len; // This will panic or abort if we would allocate > isize::MAX bytes // or if the length increment would overflow for zero-sized types. - if self.len == self.buf.capacity() { + if len == self.buf.capacity() { self.buf.grow_one(); } unsafe { - let end = self.as_mut_ptr().add(self.len); + let end = self.as_mut_ptr().add(len); ptr::write(end, value); - self.len += 1; + self.len = len + 1; } } diff --git a/tests/codegen/vec-len-invariant.rs b/tests/codegen/vec-len-invariant.rs new file mode 100644 index 00000000000..780c86bab95 --- /dev/null +++ b/tests/codegen/vec-len-invariant.rs @@ -0,0 +1,16 @@ +//@ compile-flags: -O +//@ only-64bit +// +// This test confirms that we do not reload the length of a Vec after growing it in push. + +#![crate_type = "lib"] + +// CHECK-LABEL: @should_load_once +#[no_mangle] +pub fn should_load_once(v: &mut Vec) { + // CHECK: load i64 + // CHECK: call {{.*}}grow_one + // CHECK-NOT: load i64 + // CHECK: add {{.*}}, 1 + v.push(1); +}