Skip to content

Commit cc7d801

Browse files
committed
Specialize array cloning for Copy types
Because after PR 86041, the optimizer no longer load-merges at the LLVM IR level, which might be part of the perf loss. (I'll run perf and see if this makes a difference.) Also I added a codegen test so this hopefully won't regress in future -- it passes on stable and with my change here, but not on the 2021-11-09 nightly.
1 parent 8b09ba6 commit cc7d801

File tree

2 files changed

+37
-3
lines changed

2 files changed

+37
-3
lines changed

library/core/src/array/mod.rs

+22-3
Original file line numberDiff line numberDiff line change
@@ -339,9 +339,7 @@ impl<T: Copy, const N: usize> Copy for [T; N] {}
339339
impl<T: Clone, const N: usize> Clone for [T; N] {
340340
#[inline]
341341
fn clone(&self) -> Self {
342-
// SAFETY: we know for certain that this iterator will yield exactly `N`
343-
// items.
344-
unsafe { collect_into_array_unchecked(&mut self.iter().cloned()) }
342+
SpecArrayClone::clone(self)
345343
}
346344

347345
#[inline]
@@ -350,6 +348,27 @@ impl<T: Clone, const N: usize> Clone for [T; N] {
350348
}
351349
}
352350

351+
#[cfg(not(bootstrap))]
352+
trait SpecArrayClone: Clone {
353+
fn clone<const N: usize>(array: &[Self; N]) -> [Self; N];
354+
}
355+
356+
#[cfg(not(bootstrap))]
357+
impl<T: Clone> SpecArrayClone for T {
358+
default fn clone<const N: usize>(array: &[T; N]) -> [T; N] {
359+
// SAFETY: we know for certain that this iterator will yield exactly `N`
360+
// items.
361+
unsafe { collect_into_array_unchecked(&mut array.iter().cloned()) }
362+
}
363+
}
364+
365+
#[cfg(not(bootstrap))]
366+
impl<T: Copy> SpecArrayClone for T {
367+
fn clone<const N: usize>(array: &[T; N]) -> [T; N] {
368+
*array
369+
}
370+
}
371+
353372
// The Default impls cannot be done with const generics because `[T; 0]` doesn't
354373
// require Default to be implemented, and having different impl blocks for
355374
// different numbers isn't supported yet.

src/test/codegen/array-clone.rs

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// compile-flags: -O
2+
3+
#![crate_type = "lib"]
4+
5+
// CHECK-LABEL: @array_clone
6+
#[no_mangle]
7+
pub fn array_clone(a: &[u8; 2]) -> [u8; 2] {
8+
// CHECK-NOT: getelementptr
9+
// CHECK-NOT: load i8
10+
// CHECK-NOT: zext
11+
// CHECK-NOT: shl
12+
// CHECK: load i16
13+
// CHECK-NEXT: ret i16
14+
a.clone()
15+
}

0 commit comments

Comments
 (0)