Rust でポインタを非エイリアスとして扱い、LLVM のオプティマイザで `noalias` としてマークする方法はありますか? 質問する

Rust でポインタを非エイリアスとして扱い、LLVM のオプティマイザで `noalias` としてマークする方法はありますか? 質問する

次にポインタエイリアスの例を示します。

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

が 2 回参照解除されていることに注意してください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依然として 2 回参照解除されます。

このサンプル コードが愚かであることはわかっています。パラメーターは簡単に&i32/に変更する&mut i32か、x一度逆参照して、割り当てに使用される一時的な場所に格納することができます。ここのコードは、非常に単純なエイリアシング テストを目的としており、私の質問が尋ねているより広い範囲に興味があります。

ベストアンサー1

安全な参照を関数またはクロージャでラップします。

pub unsafe fn f(a: *mut i32, b: *mut i32, x: *const i32) {
    (|safe_a: &mut i32, safe_b: &mut i32, safe_x: &i32| {
        *safe_a = *safe_x;
        *safe_b = *safe_x;
    })(&mut *a, &mut *b, &*x)
}

これにより、必要な非エイリアシング動作が生成されます。

example::f:
        movl    (%rdx), %eax
        movl    %eax, (%rdi)
        movl    %eax, (%rsi)
        retq

おすすめ記事