Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 46 additions & 1 deletion library/core/src/slice/specialize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 changes: 28 additions & 0 deletions tests/codegen-llvm/lib-optimizations/slice_fill.rs
Original file line number Diff line number Diff line change
@@ -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);
}
Loading