avoid phi node for pointers flowing into Vec appends

This commit is contained in:
The 8472 2024-09-29 00:27:50 +02:00
parent 3df0dc8803
commit 2b8f4a562f
3 changed files with 45 additions and 5 deletions

View file

@ -444,13 +444,16 @@ impl<T> [T] {
impl<T: TrivialClone> ConvertVec for T {
#[inline]
fn to_vec<A: Allocator>(s: &[Self], alloc: A) -> Vec<Self, A> {
let mut v = Vec::with_capacity_in(s.len(), alloc);
let len = s.len();
let mut v = Vec::with_capacity_in(len, alloc);
// SAFETY:
// allocated above with the capacity of `s`, and initialize to `s.len()` in
// ptr::copy_to_non_overlapping below.
unsafe {
s.as_ptr().copy_to_nonoverlapping(v.as_mut_ptr(), s.len());
v.set_len(s.len());
if len > 0 {
unsafe {
s.as_ptr().copy_to_nonoverlapping(v.as_mut_ptr(), len);
v.set_len(len);
}
}
v
}

View file

@ -2818,7 +2818,11 @@ impl<T, A: Allocator> Vec<T, A> {
let count = other.len();
self.reserve(count);
let len = self.len();
unsafe { ptr::copy_nonoverlapping(other as *const T, self.as_mut_ptr().add(len), count) };
if count > 0 {
unsafe {
ptr::copy_nonoverlapping(other as *const T, self.as_mut_ptr().add(len), count)
};
}
self.len += count;
}

View file

@ -0,0 +1,33 @@
//@ compile-flags: -O -Zmerge-functions=disabled
//@ needs-deterministic-layouts
//@ min-llvm-version: 21
#![crate_type = "lib"]
//! Check that a temporary intermediate allocations can eliminated and replaced
//! with memcpy forwarding.
//! This requires Vec code to be structured in a way that avoids phi nodes from the
//! zero-capacity length flowing into the memcpy arguments.
// CHECK-LABEL: @vec_append_with_temp_alloc
// CHECK-SAME: ptr{{.*}}[[DST:%[a-z]+]]{{.*}}ptr{{.*}}[[SRC:%[a-z]+]]
#[no_mangle]
pub fn vec_append_with_temp_alloc(dst: &mut Vec<u8>, src: &[u8]) {
// CHECK-NOT: call void @llvm.memcpy
// CHECK: call void @llvm.memcpy.{{.*}}[[DST]].i{{.*}}[[SRC]]
// CHECK-NOT: call void @llvm.memcpy
let temp = src.to_vec();
dst.extend(&temp);
// CHECK: ret
}
// CHECK-LABEL: @string_append_with_temp_alloc
// CHECK-SAME: ptr{{.*}}[[DST:%[a-z]+]]{{.*}}ptr{{.*}}[[SRC:%[a-z]+]]
#[no_mangle]
pub fn string_append_with_temp_alloc(dst: &mut String, src: &str) {
// CHECK-NOT: call void @llvm.memcpy
// CHECK: call void @llvm.memcpy.{{.*}}[[DST]].i{{.*}}[[SRC]]
// CHECK-NOT: call void @llvm.memcpy
let temp = src.to_string();
dst.push_str(&temp);
// CHECK: ret
}