about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMark Rousskov <mark.simulacrum@gmail.com>2024-04-14 11:15:00 -0400
committerMark Rousskov <mark.simulacrum@gmail.com>2024-04-20 21:07:00 -0400
commitf1ae5314bef94f1defe868cb5d78d15b5da31c8c (patch)
tree340f0c989216cc1fdf29d0f9c3ad3004ce8d23dd
parentc3ceb00281f9557dcf5bba54fc44c9931cc90d42 (diff)
downloadrust-f1ae5314bef94f1defe868cb5d78d15b5da31c8c.tar.gz
rust-f1ae5314bef94f1defe868cb5d78d15b5da31c8c.zip
Avoid reloading Vec::len across grow_one in push
This saves an extra load from memory.
-rw-r--r--library/alloc/src/vec/mod.rs8
-rw-r--r--tests/codegen/vec-len-invariant.rs16
2 files changed, 21 insertions, 3 deletions
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<T, A: Allocator> Vec<T, A> {
     #[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<u8>) {
+    // CHECK: load i64
+    // CHECK: call {{.*}}grow_one
+    // CHECK-NOT: load i64
+    // CHECK: add {{.*}}, 1
+    v.push(1);
+}