Skip to content

Commit 7ed3665

Browse files
committed
Auto merge of rust-lang#135258 - oli-obk:push-ktzskvxuwnlt, r=<try>
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.
2 parents 6afee11 + 3ca023e commit 7ed3665

File tree

2 files changed

+49
-7
lines changed

2 files changed

+49
-7
lines changed

compiler/rustc_codegen_ssa/src/mir/rvalue.rs

+21-7
Original file line numberDiff line numberDiff line change
@@ -93,23 +93,37 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
9393
return;
9494
}
9595

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

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

107111
// Use llvm.memset.p0i8.* to initialize byte arrays
108112
let v = bx.from_immediate(v);
109113
if bx.cx().val_ty(v) == bx.cx().type_i8() {
110114
bx.memset(start, v, size, dest.val.align, MemFlags::empty());
111-
return;
115+
return true;
116+
}
117+
false
118+
};
119+
120+
match cg_elem.val {
121+
OperandValue::Immediate(v) => {
122+
if try_init_all_same(bx, v) {
123+
return;
124+
}
112125
}
126+
_ => (),
113127
}
114128

115129
let count = self

tests/codegen/slice-init.rs

+28
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,34 @@ pub fn nonzero_integer_array() {
6363
opaque(&x);
6464
}
6565

66+
const N: usize = 100;
67+
68+
// FIXME: The two bytes of the u16 are the same, so we should
69+
// just use memset, too.
70+
// CHECK-LABEL: @u16_init_one_bytes
71+
#[no_mangle]
72+
pub fn u16_init_one_bytes() -> [u16; N] {
73+
// CHECK-NOT: select
74+
// CHECK-NOT: br
75+
// CHECK-NOT: switch
76+
// CHECK-NOT: icmp
77+
// CHECK: call void @llvm.memset.p0
78+
[const { u16::from_be_bytes([1, 1]) }; N]
79+
}
80+
81+
// FIXME: undef bytes can just be initialized with the same value as the
82+
// defined bytes, if the defines bytes are all the same.
83+
// CHECK-LABEL: @option_none_init
84+
#[no_mangle]
85+
pub fn option_none_init() -> [Option<u8>; N] {
86+
// CHECK-NOT: select
87+
// CHECK: br label %repeat_loop_header{{.*}}
88+
// CHECK-NOT: switch
89+
// CHECK: icmp
90+
// CHECK-NOT: call void @llvm.memset.p0
91+
[None; N]
92+
}
93+
6694
// Use an opaque function to prevent rustc from removing useless drops.
6795
#[inline(never)]
6896
pub fn opaque(_: impl Sized) {}

0 commit comments

Comments
 (0)