web-dev-qa-db-ja.com

なぜRustコンパイラーは、2つの可変参照がエイリアスできないと仮定してコードを最適化しないのですか?

私の知る限り、参照/ポインターのエイリアスは、2つの参照/ポインターが実際にエイリアスする場合に生成されたバイナリが正しく動作するようにする必要があるため、最適化されたコードを生成するコンパイラーの能力を妨げる可能性があります。たとえば、次のCコードでは、

_void adds(int  *a, int *b) {
    *a += *b;
    *a += *b;
}
_

clang version 6.0.0-1ubuntu2 (tags/RELEASE_600/final)で_-O3_フラグを指定してコンパイルすると、出力します

_0000000000000000 <adds>:
   0:    8b 07                    mov    (%rdi),%eax
   2:    03 06                    add    (%rsi),%eax
   4:    89 07                    mov    %eax,(%rdi)  # The first time
   6:    03 06                    add    (%rsi),%eax
   8:    89 07                    mov    %eax,(%rdi)  # The second time
   a:    c3                       retq
_

ここで、コードは、別名_(%rdi)_および_int *a_の場合に_int *b_に2回保存します。

これらの2つのポインターがrestrictキーワードでエイリアスできないことをコンパイラーに明示的に伝えると:

_void adds(int * restrict a, int * restrict b) {
    *a += *b;
    *a += *b;
}
_

その後、Clangはバイナリコードのより最適化されたバージョンを出力します。

_0000000000000000 <adds>:
   0:    8b 06                    mov    (%rsi),%eax
   2:    01 c0                    add    %eax,%eax
   4:    01 07                    add    %eax,(%rdi)
   6:    c3                       retq
_

Rustは(安全でないコードを除いて)2つの可変参照がエイリアスできないことを確認するので、コンパイラはより最適化されたバージョンのコードを出力できるはずだと思います。

以下のコードでテストし、_rustc 1.35.0_で_-C opt-level=3 --emit obj_でコンパイルすると、

_#![crate_type = "staticlib"]
#[no_mangle]
fn adds(a: &mut i32, b: &mut i32) {
    *a += *b;
    *a += *b;
}
_

以下を生成します。

_0000000000000000 <adds>:
   0:    8b 07                    mov    (%rdi),%eax
   2:    03 06                    add    (%rsi),%eax
   4:    89 07                    mov    %eax,(%rdi)
   6:    03 06                    add    (%rsi),%eax
   8:    89 07                    mov    %eax,(%rdi)
   a:    c3                       retq
_

これは、abがエイリアスできないという保証を利用しません。

これは、現在のRustコンパイラがまだ開発中であり、最適化を行うためにエイリアス分析をまだ組み込んでいないためですか?

これは、安全なRustでも、abがエイリアスする可能性があるためですか?

279
Zhiyao

元々の錆didはLLVMのnoalias属性を有効にしますが、これは コードのコンパイルミス です。サポートされているすべてのLLVMバージョンがコードを誤ってコンパイルしなくなったら、 再び有効になります

-Zmutable-noalias=yesをコンパイラオプションに追加すると、予想されるアセンブリが取得されます。

adds:
        mov     eax, dword ptr [rsi]
        add     eax, eax
        add     dword ptr [rdi], eax
        ret

簡単に言えば、Rust Cのrestrictキーワードに相当するものを入れてくださいeverywhere、他よりもはるかに普及しているCおよびC++プログラマーは、Rustで&mutが使用されるほど頻繁にrestrictを使用しないことが判明しました。 。

これは、複数回発生しました

  • Rust 1.0〜1.7 — noalias有効
  • Rust 1.8から1.27 — noalias無効
  • Rust 1.28から1.29 — noalias有効
  • Rust 1.30から??? — noalias無効

関連Rust issues

342
Shepmaster