I was messing around with some pointer stuff and found a weird difference in how rustc optimizes pointer operations:
For this code:
pub unsafe fn ptr_check1(p: *const u32) -> bool {
let _ = core::hint::black_box(unsafe { p.read() });
(p as usize) % 4 == 0
}
pub unsafe fn ptr_check2(p: *const u32) -> bool {
let _ = core::hint::black_box(unsafe { p.read() });
p as usize == 0
}
Compiler Explorer shows that rustc gives this output:
example::ptr_check1::h0178ece7423bdb32:
mov eax, dword ptr [rdi]
mov dword ptr [rsp - 4], eax
lea rax, [rsp - 4]
test dil, 3
sete al
ret
example::ptr_check2::h626ab988a586498e:
mov eax, dword ptr [rdi]
mov dword ptr [rsp - 4], eax
lea rax, [rsp - 4]
xor eax, eax
ret
For ptr_check2
, it uses the fact that the pointer has been read to assume that it can't have been null, so the method always returns false. This makes sense to me as an optimization that I would want it to do.
On the other hand, ptr_check1
looks to me like it should have a similar level of guarantee, since pointer::read
also requires that the pointer it's reading be aligned. However, rustc doesn't optimize this function to always return true.
Am I missing some reason why optimizing ptr_check1
to always return true wouldn't be a valid transformation? Or is this just an optimization that could be done but rustc misses?