The following example of pointer aliasing:
pub unsafe fn f(a: *mut i32, b: *mut i32, x: *const i32) {
*a = *x;
*b = *x;
}
compiles into the following assembly (with -C opt-level=s):
example::f:
push rbp
mov rbp, rsp
mov eax, dword ptr [rdx]
mov dword ptr [rdi], eax
mov eax, dword ptr [rdx]
mov dword ptr [rsi], eax
pop rbp
ret
Notice that x is being dereferenced twice. LLVM is not treating it as noalias. My first thought was to avoid using pointers in the assignments and instead use safe references (since those "follow LLVM’s scoped noalias model") to give a hint to the optimizer:
pub fn g(a: *mut i32, b: *mut i32, x: *const i32) {
let safe_a = unsafe { &mut *a };
let safe_b = unsafe { &mut *b };
let safe_x = unsafe { &*x };
*safe_a = *safe_x;
*safe_b = *safe_x;
}
But alas, this produces the exact same result. safe_x is still dereferenced twice.
I know this example code is dumb. The parameters could easily be changed to &i32/&mut i32, or I could just dereference x once and store it in a temporary that is used for the assignment. The code here is just meant to be a super simple aliasing test, and I'm interested in the broader picture my question is asking.