Description
If compiling with -Copt-level=z
we fail to remove bounds checks and panicking branches in code like this (godbolt https://godbolt.org/z/YsoMszxPe):
pub fn read_up_to_8(buf: &[u8]) -> u64 {
if buf.len() < 4 {
// actual instance has more code.
return 0;
}
let lo = u32::from_le_bytes(buf[..4].try_into().unwrap()) as u64;
let hi = u32::from_le_bytes(buf[buf.len() - 4..][..4].try_into().unwrap()) as u64;
lo | (hi << 8 * (buf.len() as u64 - 4))
}
Unfortunately, while -Copt-levels=[123s]
all manage to remove the panic branches, -Copt-level=z
does not, leading to a lot more code and significantly worse performance.
Note that we do manage to remove it in cases where the function does less stuff -- it's removed entirely in simple examples that do nothing other than load the value from a slice. However, in real code, (perhaps after a layer of inlining) you tend to have a couple of these in a function, and this issue seems to crop up again1.
Given that this pattern is more or less the recommended "safe" way to read a u32 out of a &[u8], this seems unfortunate to me.
Footnotes
-
Although not 100% reliably -- having trouble reproducing on godbolt, but it seems like it's happening in real-world code. ↩