-
Notifications
You must be signed in to change notification settings - Fork 12.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Returning MaybeUninit
const
s generates code to zero out the return value.
#83657
Comments
ManuallyDrop
const
s generates code to zero out the return value.MaybeUninit
const
s generates code to zero out the return value.
This turns into a memset when the array is large, which is significantly slower than doing nothing |
Cc @oli-obk |
Good catch! Yes we probably could be emitting proper undef constants to LLVM here (assuming LLVM has a way to let us do that). |
Oh! yea we should totally fix that. Not sure how to do it for partially initialized aggregates, but we should at least cover the fully uninit case. |
Use undef for uninitialized bytes in constants Fixes rust-lang#83657 This generates good code when the const is fully uninit, e.g. ```rust #[no_mangle] pub const fn fully_uninit() -> MaybeUninit<[u8; 10]> { const M: MaybeUninit<[u8; 10]> = MaybeUninit::uninit(); M } ``` generates ```asm fully_uninit: ret ``` as you would expect. There is no improvement, however, when it's partially uninit, e.g. ```rust pub struct PartiallyUninit { x: u64, y: MaybeUninit<[u8; 10]> } #[no_mangle] pub const fn partially_uninit() -> PartiallyUninit { const X: PartiallyUninit = PartiallyUninit { x: 0xdeadbeefcafe, y: MaybeUninit::uninit() }; X } ``` generates ```asm partially_uninit: mov rax, rdi mov rcx, qword ptr [rip + .L__unnamed_1+16] mov qword ptr [rdi + 16], rcx movups xmm0, xmmword ptr [rip + .L__unnamed_1] movups xmmword ptr [rdi], xmm0 ret .L__unnamed_1: .asciz "\376\312\357\276\255\336\000" .zero 16 .size .L__unnamed_1, 24 ``` which copies a bunch of zeros in place of the undef bytes, the same as before this change. The constant is undef where it should be, though (see the added test) so this seems to be a missed optimization in LLVM.
Use undef for uninitialized bytes in constants Fixes rust-lang#83657 This generates good code when the const is fully uninit, e.g. ```rust #[no_mangle] pub const fn fully_uninit() -> MaybeUninit<[u8; 10]> { const M: MaybeUninit<[u8; 10]> = MaybeUninit::uninit(); M } ``` generates ```asm fully_uninit: ret ``` as you would expect. There is no improvement, however, when it's partially uninit, e.g. ```rust pub struct PartiallyUninit { x: u64, y: MaybeUninit<[u8; 10]> } #[no_mangle] pub const fn partially_uninit() -> PartiallyUninit { const X: PartiallyUninit = PartiallyUninit { x: 0xdeadbeefcafe, y: MaybeUninit::uninit() }; X } ``` generates ```asm partially_uninit: mov rax, rdi mov rcx, qword ptr [rip + .L__unnamed_1+16] mov qword ptr [rdi + 16], rcx movups xmm0, xmmword ptr [rip + .L__unnamed_1] movups xmmword ptr [rdi], xmm0 ret .L__unnamed_1: .asciz "\376\312\357\276\255\336\000" .zero 16 .size .L__unnamed_1, 24 ``` which copies a bunch of zeros in place of the undef bytes, the same as before this change. The constant is undef where it should be, though (see the added test) so this seems to be a missed optimization in LLVM.
@erikdesjardins How so? Only the MaybeUninit is a constant. Which is to say that the two functions below should generate the same code: fn foo() -> ArrayVec<u8, 1000>{
ArrayVec::new()
}
fn bar() -> ArrayVec<u8, 1000> {
ArrayVec::new_const()
} Them not being equivalent was the motivation for the existence of |
Ah, you're right of course, I wasn't thinking |
I tried this code:
I expected to see this happen: Both functions to compile to just a return instruction
Instead, this happened: Only
bar
did,foo
zeros the return value in release builds.Meta
rustc --version --verbose
:The text was updated successfully, but these errors were encountered: