Change:
} #[no_mangle] <del> // CHECK-LABEL: @replace_short_array( pub fn replace_short_array(r: &mut [u32; 3], v: [u32; 3]) -> [u32; 3] { </del> <ins> // CHECK-LABEL: @replace_short_array_3( pub fn replace_short_array_3(r: &mut [u32; 3], v: [u32; 3]) -> [u32; 3] { </ins> // CHECK-NOT: alloca <del> // CHECK: %[[R:.+]] = load <3 x i32>, ptr %r, align 4 // CHECK: store <3 x i32> %[[R]], ptr %result // CHECK: %[[V:.+]] = load <3 x i32>, ptr %v, align 4 // CHECK: store <3 x i32> %[[V]], ptr %r </del> <ins> // CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %result, ptr align 4 %r, i64 12, i1 false) // CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %r, ptr align 4 %v, i64 12, i1 false) std::mem::replace(r, v) } #[no_mangle] // CHECK-LABEL: @replace_short_array_4( pub fn replace_short_array_4(r: &mut [u32; 4], v: [u32; 4]) -> [u32; 4] { // CHECK-NOT: alloca // CHECK: %[[R:.+]] = load <4 x i32>, ptr %r, align 4 // CHECK: store <4 x i32> %[[R]], ptr %result // CHECK: %[[V:.+]] = load <4 x i32>, ptr %v, align 4 // CHECK: store <4 x i32> %[[V]], ptr %r </ins> std::mem::replace(r, v) }

Discussion:
<!-- Thank you for filing a regression report! A regression is something that changed between versions of Rust but was not supposed to. Please provide a short summary of the regression, along with any information you feel is relevant to replicate it. --Nearly 50% performance regression between versions 1.71 and 1.72 when copying small byte arrays with platform (Macbook Pro M1). Used to track down the regression to I tried this code: I expected to see this happen: to run about 6,200,000 ns/iter like version 1.71 Instead, this happened: 9,159,412 ns/iter <!-- Provide the most recent version this worked on, for example: It most recently worked on: Rust 1.47 --It most recently worked on: 1.71 More specifically nightly-2023-06-06-aarch64-apple-darwin 72 nightly-2023-06-07-aarch64-apple-darwin <!-- Provide the version you are using that has the regression. --: Searched nightlies: from nightly-2023-06-06 to nightly-2023-06-07 regressed nightly: nightly-2023-06-07 searched commit range: regressed commit: <details<summarybisected with <a href=''cargo-bisect-rustc</av0.6.7</summaryHost triple: x86_64-apple-darwin Reproduce with: </details modify labels: +regression-from-stable-to-stable -regression-untriaged
Here's a demo for :
Oof, that's massively worse. But even with a nice size (), it's still a small regression: We should probably revert , or limit it to very small arrays (<= 8 bytes / 1 usize? )
The original motivation of that PR is for arrays larger than that, so I'm not so sure. If I strip this down to just the pointer write it's not as bad, but it's quite clear that the problem is just x86-isel: Is that even good instruction selection?

Hmm, curiously looking at just the part of the push logic that copies the value, the assembly is entirely reasonable: then in the context of a "real" push, it somehow still blows up:
Here's a small tweak to try to fix this for 1.73:
I've opened to track the suboptimal codegen mentioned in Once a new nightly is out, please give it a shot and reopen if you're still seeing the regression.
On Ubuntu VM running on Ryzen 5950X this is far worse: 4x regression.
Things look much better with . Thanks for the quick fix!
Thanks for confirming! I'll see if it can make 1.73.