次のポインターのエイリアシングの例:
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
が 2 回逆参照されていることに注意してください。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
まだ 2 回逆参照されています。
このサンプルコードがばかげていることはわかっています。&i32
パラメーターは/に簡単に変更できます&mut i32
。または、一度逆参照x
して、割り当てに使用される一時変数に格納することもできます。ここのコードは、非常に単純なエイリアシング テストを意図したものであり、私の質問が求めているより広い視野に興味があります。