Skip to content

Commit 240d5e4

Browse files
committed
test that the phi node got eliminated
1 parent 820e27a commit 240d5e4

File tree

3 files changed

+47
-5
lines changed

3 files changed

+47
-5
lines changed

library/alloc/src/slice.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ use crate::borrow::ToOwned;
6868
use crate::boxed::Box;
6969
use crate::vec::Vec;
7070

71+
7172
impl<T> [T] {
7273
/// Sorts the slice in ascending order, preserving initial order of equal elements.
7374
///
@@ -446,6 +447,12 @@ impl<T> [T] {
446447
impl<T: Copy> ConvertVec for T {
447448
#[inline]
448449
fn to_vec<A: Allocator>(s: &[Self], alloc: A) -> Vec<Self, A> {
450+
if s.is_empty() {
451+
// The early return is not necessary for correctness, but it helps
452+
// LLVM by avoiding phi nodes flowing into memcpy.
453+
// See codegen/lib-optimizations/append-elements.rs
454+
return Vec::new_in(alloc);
455+
}
449456
let mut v = Vec::with_capacity_in(s.len(), alloc);
450457
// SAFETY:
451458
// allocated above with the capacity of `s`, and initialize to `s.len()` in

library/alloc/src/vec/mod.rs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2590,11 +2590,9 @@ impl<T, A: Allocator> Vec<T, A> {
25902590
unsafe fn append_elements(&mut self, other: *const [T]) {
25912591
let count = other.len();
25922592
if count == 0 {
2593-
// The early return is not necessary for correctness, but in cases
2594-
// where LLVM sees all the way to the allocation site of `other`
2595-
// this can avoid a phi-node merging the two different pointers
2596-
// when zero-length allocations are special-cased.
2597-
// That in turn can enable more optimizations around the memcpy below.
2593+
// The early return is not necessary for correctness, but it helps
2594+
// LLVM by avoiding phi nodes flowing into memcpy.
2595+
// See codegen/lib-optimizations/append-elements.rs
25982596
return;
25992597
}
26002598
self.reserve(count);
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
//@ compile-flags: -O -Zmerge-functions=disabled
2+
#![crate_type = "lib"]
3+
4+
//! Check that pointer flowing into vec.append comes straight from an allocation
5+
//! and not through a phi node that merges the allocation and zero-length cases.
6+
//! With this and https://github.com/llvm/llvm-project/pull/110280 the intermediate
7+
//! allocation should be optimized away in the future.
8+
9+
// CHECK-LABEL: @vec_append_with_temp_alloc
10+
#[no_mangle]
11+
pub fn vec_append_with_temp_alloc(dst: &mut Vec<u8>, src: &[u8]) {
12+
// CHECK: %[[TEMP:.+]] = tail call noalias noundef ptr @{{.*}}__rust_alloc
13+
14+
// First memcpy, it uses the src pointer directly
15+
// CHECK: call void @llvm.memcpy.{{.*}}%src.0
16+
let temp = src.to_vec();
17+
18+
// final memcpy to destination
19+
// CHECK: call void @llvm.memcpy.{{.*}}%dst.i{{.*}}%[[TEMP]]
20+
dst.extend(&temp);
21+
// CHECK: ret
22+
}
23+
24+
// CHECK-LABEL: @string_append_with_temp_alloc
25+
#[no_mangle]
26+
pub fn string_append_with_temp_alloc(dst: &mut String, src: &str) {
27+
// CHECK: %[[TEMP:.+]] = tail call noalias noundef ptr @__rust_alloc
28+
29+
// First memcpy, it uses the src pointer directly
30+
// CHECK: call void @llvm.memcpy.{{.*}}%src.0
31+
let temp = src.to_string();
32+
33+
// final memcpy to destination
34+
// CHECK: call void @llvm.memcpy.{{.*}}%dst.i{{.*}}%[[TEMP]]
35+
dst.push_str(&temp);
36+
// CHECK: ret
37+
}

0 commit comments

Comments
 (0)