Closed
Description
I tried this code:
pub fn ipv4_bitand_mask(ipv4: Ipv4Addr, mask: u32) -> Ipv4Addr {
let ipv4_u32 = u32::from_ne_bytes(ipv4.octets());
Ipv4Addr::from((ipv4_u32 & mask).to_ne_bytes())
}
I expected to see this happen: assembly generated should be equivalent to:
pub fn ipv4_bitand_mask_unsafe(ipv4: Ipv4Addr, mask: u32) -> Ipv4Addr {
let ipv4_u32: u32 = unsafe { std::mem::transmute(ipv4) };
unsafe { std::mem::transmute(ipv4_u32 & mask) }
}
Instead, this happened: the generated assembly retains calls to Ipv4::octets and Ipv4::from, leaving the assembly poorly optimized
I've played with different ways of implementing the safe version, but cannot find anyway get it to optimize further.
Good assembly:
example::ipv4_bitand_mask_unsafe:
mov eax, edi
and eax, esi
ret
Bad assembly:
example::ipv4_bitand_mask:
push rbx
sub rsp, 16
mov ebx, esi
mov dword ptr [rsp + 8], edi
lea rdi, [rsp + 8]
call qword ptr [rip + std::net::ip::Ipv4Addr::octets@GOTPCREL]
and eax, ebx
mov edi, eax
call qword ptr [rip + <std::net::ip::Ipv4Addr as core::convert::From<[u8; 4]>>::from@GOTPCREL]
add rsp, 16
pop rbx
ret
Playground and GodBolt (both include an IPv6 example as well)
Adding '-Z mir-opt-level=2' (or higher) does optimize away the call to octets, but not the call to from.
I get the same optimization behavior when building a binary, at least on my own platfom (x86-64 Windows MSVC)
Meta
rustc --version --verbose
:
rustc 1.49.0-nightly (beb5ae474 2020-10-04)
binary: rustc
commit-hash: beb5ae474d2835962ebdf7416bd1c9ad864fe101
commit-date: 2020-10-04
host: x86_64-pc-windows-msvc
release: 1.49.0-nightly
LLVM version: 11.0