Skip to content

Commit a7b39f6

Browse files
committed
specialize slice::fill to use memset when possible
LLVM generally can do this on its own, but it helps miri and other backends.
1 parent 2cb4e7d commit a7b39f6

File tree

2 files changed

+54
-1
lines changed

2 files changed

+54
-1
lines changed

library/core/src/slice/specialize.rs

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,34 @@ impl<T: Clone> SpecFill<T> for [T] {
1515
}
1616

1717
impl<T: Copy> SpecFill<T> for [T] {
18-
fn spec_fill(&mut self, value: T) {
18+
default fn spec_fill(&mut self, value: T) {
1919
for item in self.iter_mut() {
2020
*item = value;
2121
}
2222
}
2323
}
24+
25+
macro spec_fill_int {
26+
($($type:ty)*) => {$(
27+
impl SpecFill<$type> for [$type] {
28+
#[inline]
29+
fn spec_fill(&mut self, value: $type) {
30+
if cfg!(miri) || crate::intrinsics::is_val_statically_known(value) {
31+
let bytes = value.to_ne_bytes();
32+
if value == <$type>::from_ne_bytes([bytes[0]; size_of::<$type>()]) {
33+
// SAFETY: The pointer is derived from a reference, so it's writable.
34+
unsafe {
35+
crate::intrinsics::write_bytes(self.as_mut_ptr(), bytes[0], self.len());
36+
}
37+
return;
38+
}
39+
}
40+
for item in self.iter_mut() {
41+
*item = value;
42+
}
43+
}
44+
}
45+
)*}
46+
}
47+
48+
spec_fill_int! { u8 i8 u16 i16 u32 i32 u64 i64 u128 i128 usize isize }
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
//@ compile-flags: -Copt-level=3
2+
#![crate_type = "lib"]
3+
4+
use std::mem::MaybeUninit;
5+
6+
// CHECK-LABEL: @slice_fill_pass_undef
7+
#[no_mangle]
8+
pub fn slice_fill_pass_undef(s: &mut [MaybeUninit<u8>], v: MaybeUninit<u8>) {
9+
// CHECK: tail call void @llvm.memset.{{.*}}(ptr nonnull align 1 %s.0, i8 %v, {{.*}} %s.1, i1 false)
10+
// CHECK: ret
11+
s.fill(v);
12+
}
13+
14+
// CHECK-LABEL: @slice_fill_uninit
15+
#[no_mangle]
16+
pub fn slice_fill_uninit(s: &mut [MaybeUninit<u8>]) {
17+
// CHECK-NOT: call
18+
// CHECK: ret void
19+
s.fill(MaybeUninit::uninit());
20+
}
21+
22+
// CHECK-LABEL: @slice_wide_memset
23+
#[no_mangle]
24+
pub fn slice_wide_memset(s: &mut [u16]) {
25+
// CHECK: tail call void @llvm.memset.{{.*}}(ptr nonnull align 2 %s.0, i8 -1
26+
// CHECK: ret
27+
s.fill(0xFFFF);
28+
}

0 commit comments

Comments
 (0)