以下是指针别名的示例:
pub unsafe fn f(a: *mut i32, b: *mut i32, x: *const i32) {
*a = *x;
*b = *x;
}
经过 -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
请注意x
被解引用了两次,LLVM没有将其视为noalias
。我的第一个想法是避免在赋值中使用指针,而是使用安全的引用(因为这些引用“遵循LLVM的作用域noalias
模型”),以提示优化器:
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;
}
但是不幸的是,这会产生完全相同的结果。 safe_x
仍会被解引用两次。
我知道这个示例代码很愚蠢。参数可以很容易地更改为&i32
/ &mut i32
,或者我可以只解引用x
一次,并将其存储在临时变量中,该变量用于赋值。这里的代码只是一个超级简单的别名测试,我对我的问题所问的更广泛的情况感兴趣。
&mut i32、&mut i32、&i32
作为原型,那么noalias
属性将附加到x
上。我似乎记得noalias
不会被主动传递给LLVM,因为存在需要先澄清unsafe
语义,然后再应用优化的担忧,以免LLVM“破坏”代码。 - Matthieu M.Unique<T>
- Lukas Kalbertodt