specialize slice::fill to use memset when possible
LLVM generally can do this on its own, but it helps miri and other backends.
This commit is contained in:
@@ -15,9 +15,54 @@ impl<T: Clone> SpecFill<T> for [T] {
|
||||
}
|
||||
|
||||
impl<T: Copy> SpecFill<T> for [T] {
|
||||
fn spec_fill(&mut self, value: T) {
|
||||
default fn spec_fill(&mut self, value: T) {
|
||||
for item in self.iter_mut() {
|
||||
*item = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SpecFill<u8> for [u8] {
|
||||
fn spec_fill(&mut self, value: u8) {
|
||||
// SAFETY: The pointer is derived from a reference, so it's writable.
|
||||
unsafe {
|
||||
crate::intrinsics::write_bytes(self.as_mut_ptr(), value, self.len());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SpecFill<i8> for [i8] {
|
||||
fn spec_fill(&mut self, value: i8) {
|
||||
// SAFETY: The pointer is derived from a reference, so it's writable.
|
||||
unsafe {
|
||||
crate::intrinsics::write_bytes(self.as_mut_ptr(), value.cast_unsigned(), self.len());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro spec_fill_int {
|
||||
($($type:ty)*) => {$(
|
||||
impl SpecFill<$type> for [$type] {
|
||||
#[inline]
|
||||
fn spec_fill(&mut self, value: $type) {
|
||||
// We always take this fastpath in Miri for long slices as the manual `for`
|
||||
// loop can be prohibitively slow.
|
||||
if (cfg!(miri) && self.len() > 32) || crate::intrinsics::is_val_statically_known(value) {
|
||||
let bytes = value.to_ne_bytes();
|
||||
if value == <$type>::from_ne_bytes([bytes[0]; size_of::<$type>()]) {
|
||||
// SAFETY: The pointer is derived from a reference, so it's writable.
|
||||
unsafe {
|
||||
crate::intrinsics::write_bytes(self.as_mut_ptr(), bytes[0], self.len());
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
for item in self.iter_mut() {
|
||||
*item = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
)*}
|
||||
}
|
||||
|
||||
spec_fill_int! { u16 i16 u32 i32 u64 i64 u128 i128 usize isize }
|
||||
|
||||
28
tests/codegen-llvm/lib-optimizations/slice_fill.rs
Normal file
28
tests/codegen-llvm/lib-optimizations/slice_fill.rs
Normal file
@@ -0,0 +1,28 @@
|
||||
//@ compile-flags: -Copt-level=3
|
||||
#![crate_type = "lib"]
|
||||
|
||||
use std::mem::MaybeUninit;
|
||||
|
||||
// CHECK-LABEL: @slice_fill_pass_undef
|
||||
#[no_mangle]
|
||||
pub fn slice_fill_pass_undef(s: &mut [MaybeUninit<u8>], v: MaybeUninit<u8>) {
|
||||
// CHECK: tail call void @llvm.memset.{{.*}}(ptr nonnull align 1 %s.0, i8 %v, {{.*}} %s.1, i1 false)
|
||||
// CHECK: ret
|
||||
s.fill(v);
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @slice_fill_uninit
|
||||
#[no_mangle]
|
||||
pub fn slice_fill_uninit(s: &mut [MaybeUninit<u8>]) {
|
||||
// CHECK-NOT: call
|
||||
// CHECK: ret void
|
||||
s.fill(MaybeUninit::uninit());
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @slice_wide_memset
|
||||
#[no_mangle]
|
||||
pub fn slice_wide_memset(s: &mut [u16]) {
|
||||
// CHECK: tail call void @llvm.memset.{{.*}}(ptr nonnull align 2 %s.0, i8 -1
|
||||
// CHECK: ret
|
||||
s.fill(0xFFFF);
|
||||
}
|
||||
Reference in New Issue
Block a user