Skip to content

Commit

Permalink
Auto merge of rust-lang#135258 - oli-obk:push-ktzskvxuwnlt, r=<try>
Browse files Browse the repository at this point in the history
Use llvm.memset.p0i8.* to initialize all same-bytes arrays

It doesn't affect tests, LLVM seems smart enough for it, but then I wonder why we have the zero case at all (it was introduced in rust-lang#43488, maybe LLVM wasn't smart enough then). So let's run perf to see if there's any build time effect, and if no, I'll remove the zero special case and also run perf.
  • Loading branch information
bors committed Jan 8, 2025
2 parents 6afee11 + 3ca023e commit 7ed3665
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 7 deletions.
28 changes: 21 additions & 7 deletions compiler/rustc_codegen_ssa/src/mir/rvalue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,23 +93,37 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
return;
}

if let OperandValue::Immediate(v) = cg_elem.val {
let try_init_all_same = |bx: &mut Bx, v| {
let start = dest.val.llval;
let size = bx.const_usize(dest.layout.size.bytes());

// Use llvm.memset.p0i8.* to initialize all zero arrays
if bx.cx().const_to_opt_u128(v, false) == Some(0) {
let fill = bx.cx().const_u8(0);
bx.memset(start, fill, size, dest.val.align, MemFlags::empty());
return;
// Use llvm.memset.p0i8.* to initialize all same byte arrays
if let Some(int) = bx.cx().const_to_opt_u128(v, false) {
let bytes = &int.to_le_bytes()[..cg_elem.layout.size.bytes_usize()];
let first = bytes[0];
if bytes[1..].iter().all(|&b| b == first) {
let fill = bx.cx().const_u8(first);
bx.memset(start, fill, size, dest.val.align, MemFlags::empty());
return true;
}
}

// Use llvm.memset.p0i8.* to initialize byte arrays
let v = bx.from_immediate(v);
if bx.cx().val_ty(v) == bx.cx().type_i8() {
bx.memset(start, v, size, dest.val.align, MemFlags::empty());
return;
return true;
}
false
};

match cg_elem.val {
OperandValue::Immediate(v) => {
if try_init_all_same(bx, v) {
return;
}
}
_ => (),
}

let count = self
Expand Down
28 changes: 28 additions & 0 deletions tests/codegen/slice-init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,34 @@ pub fn nonzero_integer_array() {
opaque(&x);
}

const N: usize = 100;

// FIXME: The two bytes of the u16 are the same, so we should
// just use memset, too.
// CHECK-LABEL: @u16_init_one_bytes
#[no_mangle]
pub fn u16_init_one_bytes() -> [u16; N] {
// CHECK-NOT: select
// CHECK-NOT: br
// CHECK-NOT: switch
// CHECK-NOT: icmp
// CHECK: call void @llvm.memset.p0
[const { u16::from_be_bytes([1, 1]) }; N]
}

// FIXME: undef bytes can just be initialized with the same value as the
// defined bytes, if the defines bytes are all the same.
// CHECK-LABEL: @option_none_init
#[no_mangle]
pub fn option_none_init() -> [Option<u8>; N] {
// CHECK-NOT: select
// CHECK: br label %repeat_loop_header{{.*}}
// CHECK-NOT: switch
// CHECK: icmp
// CHECK-NOT: call void @llvm.memset.p0
[None; N]
}

// Use an opaque function to prevent rustc from removing useless drops.
#[inline(never)]
pub fn opaque(_: impl Sized) {}

0 comments on commit 7ed3665

Please sign in to comment.